Skip to content

Add adapter health-probe method + source-aware /readyz and nautilus health --sources #121

Description

@se-jo-ma

Context

Readiness today proves the session store works, not that data backends are reachable. /readyz (nautilus/transport/fastapi_app.py:326-356) returns 200 iff lifespan startup finished AND store.aget(_READY_PROBE_KEY) succeeds against the session store — it never touches any configured data source. A broker can therefore advertise "ready" while every backend is down; source failures only surface as per-request sources_errored entries (broker lazy-connects on first request, broker.py:1620-1631). Operators have no preflight for source connectivity short of issuing a real request.

The Adapter Protocol (nautilus/adapters/base.py:153) currently defines only connect, execute, close, get_schema — there is no health/ping surface (grep for ping|health_check|aping|verify_connectivity across the 8 adapter modules returns nothing). The CLI health subcommand (nautilus/cli/health.py) just GETs /readyz.

Task

  • Add a lightweight liveness-probe capability to adapters (e.g. async def aping(self) -> None) and implement per-backend checks in the built-in adapters (SELECT 1, ES ping, Neo4j verify_connectivity, etc.).
  • Extend /readyz with an opt-in source-aware mode (?sources=true or a separate /readyz/sources) that aggregates adapter probes and returns per-source up/down status without leaking DSNs or credentials.
  • Add nautilus health --sources to surface the same matrix from the CLI.

Where

  • nautilus/adapters/base.py:153 — the Adapter Protocol
  • The 8 built-in adapter modules: postgres.py, pgvector.py, elasticsearch.py, neo4j.py, rest.py, servicenow.py, influxdb.py, s3.py
  • nautilus/transport/fastapi_app.py:326-356readyz handler
  • nautilus/cli/health.py and CLI wiring in nautilus/cli/__init__.py:267-268

Decision needed (do not skip)

The proposal's "default no-op on the Protocol" detail collides with existing design rationale. base.py:152-170 explicitly documents why members are NOT added to the @runtime_checkable Protocol when they would break isinstance/type[Adapter] assignability, and get_schema was deliberately a default-raising method, not a silent no-op. The broker's structural adapter check (broker.py:154) validates only connect/execute/close. Pick one before coding: (a) Protocol method with a benign default, (b) optional capability detected via hasattr/registry (mirrors how capabilities is handled), or (c) reuse connect() as the probe. Resolve this with a maintainer.

Acceptance criteria

  • Default /readyz semantics are unchanged (back-compat — still 200 only when startup done + session store reachable).
  • The source-aware probe reports each source up/down independently; a down source is reflected without exposing credentials or DSNs (consistent with the credential-free /v1/sources listing at fastapi_app.py:300-319).
  • Adapters without a concrete probe override do not raise NotImplementedError from the aggregated probe path.
  • nautilus health --sources prints the same matrix and exits non-zero when any source is down.
  • Unit + integration tests cover both the per-adapter probe and the aggregated endpoint (probes against testcontainer-backed adapters under -m integration).

Size: M

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium priority: v2 epic or non-blocking gaparea/adaptersAdapter SDK + built-in adaptersarea/clinautilus CLI commandsarea/coreBroker core, CLIPS routing, session stateenhancementNew feature or requestneeds-decisionApproach not yet settled — please don't open a PR yetsize/M<2 days: multi-file feature

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions