Skip to content

feat: run user-supplied health probes on every health check route - #297

Merged
lesnik512 merged 1 commit into
mainfrom
feat/health-probes
Oct 22, 2026
Merged

lesnik512 merged 1 commit into
mainfrom
feat/health-probes

Conversation

@lesnik512

Copy link
Copy Markdown
Member

Closes #294.

The Litestar, FastAPI and FastMCP health check routes always answered health_status: true, and the FastStream route could only ping its brokers. A service whose database or cache was down still reported healthy.

HealthChecksConfig gains health_checks_probes: Mapping[str, HealthProbe], where HealthProbe is Callable[[], Awaitable[bool]]. It is empty by default. On every request the health check route on Litestar, FastAPI, FastMCP and FastStream runs all probes concurrently. On FastStream they run alongside the broker pings from #296, and everything must pass.

  • A probe fails when it returns False or raises. A raised exception stays inside the route and is logged as one warning with the probe's name and the traceback, without the callable's repr. A False result logs one warning with the name.
  • Healthy is 200 with the existing JSON body. Unhealthy is 500 with the same body and health_status: false, on all four frameworks. The body does not name failing probes.
  • lite-bootstrap enforces no timeout. The docs tell users to bound each probe themselves, for example functools.partial(broker.ping, timeout=5), and warn that a probe on an external dependency makes a liveness route restart pods during that dependency's outage.

Following ADR 0002, the shared logic sits in HealthChecksInstrument.define_health_status(). Framework subclasses only bind the route and pick the status code. FastStream overrides _define_framework_health_status() with its broker pings, so pings and probes run in a single asyncio.gather. render_health_check_data() takes an optional keyword-only health_status, so existing callers are unaffected.

Behavior change: FastStream's unhealthy response is now the JSON body with health_status: false instead of the plain-text Service is unhealthy. The status code stays 500.

With no probes registered, the Litestar, FastAPI and FastMCP routes respond exactly as before, and their existing tests pass unchanged.

CONTEXT.md adds the term Health probe, carried over from the maintainer's draft.

Tests, written first: a parametrized test on each of the four frameworks (all pass, one returns False, one raises) that checks the status, the body and which probes were logged. A FastStream test checks that a passing probe with a failing broker ping gives 500. A base instrument test checks that two probes sleeping 0.2 s each finish in under 0.3 s.

Out of scope: #295, an enforced timeout, FreeBootstrapper, and separate liveness and readiness routes.

@lesnik512
lesnik512 merged commit 9484afa into main Oct 22, 2026
30 checks passed
@lesnik512
lesnik512 deleted the feat/health-probes branch October 22, 2026 05:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

User-supplied health probes for every bootstrapper with a health check

1 participant