Skip to content

[Feature]: Readiness/liveness health probes and graceful shutdown with in-flight request draining #1009

Description

@pavsoss

Problem

/health returns a static {"status": "ok"} regardless of whether the model is loaded or dependencies (spam-words SQLite, rate-limit store) are reachable, so an orchestrator can route traffic to an instance that will 5xx every prediction. There is also no graceful shutdown: a SIGTERM drops in-flight requests immediately.

Proposed solution

Split health into liveness and readiness, make readiness reflect real dependencies, and drain in-flight requests on shutdown.

Scope

  • GET /health/live — process is up (always 200).
  • GET /health/ready — 200 only when the serving state is populated and the spam-words DB + rate-limit store respond; otherwise 503 with the standard error envelope ([Feature]: Standardize Flask ML API errors behind a machine-readable error envelope (backward compatible) #986).
  • Keep GET /health as a backward-compatible alias.
  • Track in-flight requests in before_request/after_request.
  • A SIGTERM handler that flips readiness to draining (so /health/ready returns 503 and load balancers stop routing), waits for in-flight requests to finish up to a bounded timeout, then exits.
  • README + OpenAPI paths; regression coverage for ready/live states and the drain flag.

Acceptance criteria

  • /health/ready is 503 before the model loads / when a dependency is down, and 200 otherwise; /health/live is independent of dependencies.
  • /health still responds as today (no breaking change).
  • After SIGTERM, readiness reports draining and in-flight requests complete before exit (covered by a test with a fake slow request).

Out of scope

Kubernetes manifests/probe configuration; multi-process (gunicorn) worker coordination.

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions