Health API
Check the overall health of the InfoConnect Hybrid Search Engine.
Endpoint
GET /health
Request
No authentication required for health checks.
Response
Healthy
{
"status": "healthy",
"version": "0.5.15",
"components": {
"api": "ok",
"redis": "ok",
"qdrant": "ok",
"celery": "ok",
"publication": "ok"
},
"publishing": {
"status": "ready",
"reason": null,
"authority_mode": "READY"
},
"diagnostics": {
"publication": {
"status": "ready",
"serving_status": "ready",
"publishing_status": "ready",
"authority_mode": "READY"
}
}
}
Safe publication fencing
Publication writes pause while the deployment-wide fence is active, but the last
ready snapshot remains safe for reads. The endpoint stays HTTP 200 and
top-level status stays healthy when all serving components are healthy:
{
"status": "healthy",
"version": "0.5.15",
"components": {
"api": "ok",
"redis": "ok",
"qdrant": "ok",
"celery": "ok",
"publication": "ok"
},
"publishing": {
"status": "degraded",
"reason": "fencing",
"authority_mode": "FENCING"
},
"diagnostics": {
"publication": {
"status": "ready",
"serving_status": "ready",
"publishing_status": "degraded",
"authority_mode": "FENCING"
}
}
}
Degraded dependency
{
"status": "degraded",
"version": "0.5.15",
"components": {
"api": "ok",
"redis": "error",
"qdrant": "ok",
"celery": "ok",
"publication": "ok"
},
"publishing": {
"status": "ready",
"reason": null,
"authority_mode": "READY"
}
}
Version Field
The top-level version field is the Product Version of the running service. It is derived from the package version in pyproject.toml, not from a separately edited health-check constant. Use it to confirm which release is actually serving traffic after a deploy, rollback, or local rebuild.
The same Product Version also appears as info.version in /openapi.json. Run just version-check before release work to verify that pyproject.toml, runtime metadata, app.version, /health, and the committed OpenAPI document agree.
Component Status
| Component | Description |
|---|---|
api | FastAPI application status |
redis | Application-state Redis connection |
qdrant | Qdrant vector database connection |
celery | Always ok. Kept for response compatibility; /health does not probe Celery workers. Watch worker backlog through /metrics infoconnect_queue_depth and just status |
publication | Publication-backed read-serving safety (only when PUBLICATION_ENABLED=true) |
modernbert-onnx | ModernBERT ONNX classification model health (when CLASSIFICATION_ENABLED=true; omitted when classification is off) |
Publication-enabled responses include two distinct typed signals:
components.publicationand top-levelstatusdescribe whether this API process can safely serve publication-backed reads.READYandFENCINGare serving-safe only while the local request gate is valid and the worker safe-serving deadline is live.publishingdescribes immediate write admission. It isreadyinREADY,degradedwith reasonfencingin serving-safeFENCING, andunavailableinRECOVERING,MAINTENANCE, when authority data is unreadable or missing, when the local gate is invalidated, or when the worker deadline expires.
Generation cleanup does not enter MAINTENANCE; see the
cleanup contract.
When publication is disabled, publishing is still present with status: "ready",
reason: null, and authority_mode: "DISABLED"; the publication component and
diagnostics are omitted.
diagnostics.publication exposes typed serving_status, publishing_status, and
authority_mode values plus bounded authority, Redis, Qdrant, collection-schema, and
recovery-evidence identifiers. Publication readiness and diagnostic reads each have a two-second
deadline. The Qdrant version and collection-schema digest come from a cached read with a
five-minute maximum age. In-process lane or index provisioning invalidates the cache even if
provisioning only partially succeeds. The next probe after invalidation or expiry re-reads the
four publication lane schemas; no background refresh runs. A probe racing provisioning can
cache the earlier schema until expiry. Backup and restore compatibility checks use a fresh,
uncached read.
Serving failures fail closed immediately. Any state other than READY or serving-safe FENCING
sets components.publication to error and returns HTTP 503 on the first sample. This includes
RECOVERING, MAINTENANCE, unreadable or missing authority, invalidated gates, expired worker
deadlines, and probe timeouts. Serving-safe FENCING also keeps HTTP 200;
its separate publishing signal remains degraded.
Examples
Basic Health Check
curl http://localhost:8000/health
Monitoring Script
#!/bin/bash
response=$(curl -s http://localhost:8000/health)
status=$(echo "$response" | jq -r '.status')
version=$(echo "$response" | jq -r '.version')
if [ "$status" = "healthy" ]; then
echo "✅ System is healthy (version $version)"
exit 0
else
echo "❌ System is degraded (version $version)"
echo "$response" | jq '.'
exit 1
fi
Docker Health Check
Use the healthcheck in docker-compose.prod.yml for production; see
Production container healthcheck for its detection bound
and startup grace period. The base docker-compose.yml retains its development/QA probe cadence.
Kubernetes Liveness Probe
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 60
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
Load Balancer Health Check
Configure your load balancer to ping /health every 30 seconds. Publication serving failures
return 503 and remove the instance from rotation through ordinary HTTP health checks. A safe
publication fence returns 200: reads continue from pinned snapshots while
publishing.status="degraded" identifies paused write activation. Other component failures return
a degraded body with HTTP 200; use a body-aware monitor if those failures should also remove an
instance.
Response Codes
| Code | Status | Description |
|---|---|---|
| 200 | Healthy or degraded | Read serving is safe; inspect publishing, status, and components for paused publication writes or other dependency failures |
| 503 | Degraded | Publication is enabled and read serving is unsafe; the first unsafe sample fails closed |
Use top-level status and components.publication for serving availability. Alert independently
on publishing.status: safe FENCING intentionally keeps the instance in rotation while new
activation waits. A publication 503 remains fail-closed when no safe pinned view can be served.
Troubleshooting
Redis Error
{
"status": "degraded",
"components": {
"redis": "error"
}
}
Check: Redis container is running
docker compose ps redis
docker compose logs redis
Qdrant Error
{
"status": "degraded",
"components": {
"qdrant": "error"
}
}
Check: Qdrant container is running
docker compose ps qdrant
curl http://localhost:6333/healthz
Celery workers
components.celery is always ok; /health does not check workers. To see whether workers are
draining work, check queue depth and worker processes:
curl -s http://localhost:8000/metrics | grep infoconnect_queue_depth
just status
Production container healthcheck
The production API container probes /health every 60 seconds with a 10-second timeout and
2 retries, so a dead API is marked unhealthy within 140 seconds (retries × (interval + timeout))
of its last good probe after startup grace has ended. During the first 10 minutes after start
(start_period), the container probes every 10 seconds and failures do not count until a probe
succeeds, because publication recovery and model loading keep :8000 closed for several minutes.
The startup probe interval requires Docker Engine 25 or newer. unhealthy does not restart the
container; route it to your monitor. Production deployment waits by requesting /health
directly; no Compose service depends on API container health. See docker-compose.prod.yml.
Best Practices
- Monitor continuously - Use
/healthfor uptime monitoring - Alert on degraded - Set up alerts when status != healthy
- Check components - Inspect individual component status for debugging
- Log responses - Log health check results for troubleshooting