feat(cloud-api): expose health readiness

This commit is contained in:
2026-07-12 18:33:45 +08:00
parent b8d02abf87
commit a5de7399f8
3 changed files with 112 additions and 2 deletions
+38 -1
View File
@@ -7,7 +7,8 @@ from contextlib import asynccontextmanager
from dataclasses import dataclass
from typing import Any
from fastapi import FastAPI
from fastapi import FastAPI, status
from fastapi.responses import JSONResponse
from cloud.auth import create_auth_provider
from cloud.config import CloudConfig
@@ -90,12 +91,15 @@ def create_app(
app.state.cloud_config = control_config
app.state.database = database
app.state.cloud_services = services
app.state.startup_complete = False
app.state.schema_ready = False
stop_workers = asyncio.Event()
worker_tasks: list[asyncio.Task[None]] = []
try:
repository.health_check()
if control_config.environment == "production":
require_current_schema(control_config.database_url)
app.state.schema_ready = True
worker_tasks = [
asyncio.create_task(
_run_scheduler_loop(
@@ -116,8 +120,10 @@ def create_app(
),
]
app.state.worker_tasks = tuple(worker_tasks)
app.state.startup_complete = True
yield
finally:
app.state.startup_complete = False
stop_workers.set()
try:
if worker_tasks:
@@ -129,6 +135,37 @@ def create_app(
repository.unbind()
app = FastAPI(title="Device Cloud API", lifespan=lifespan)
@app.get("/health/live")
def health_live() -> dict[str, str]:
return {"status": "live"}
@app.get("/health/ready")
def health_ready():
checks = {
"configuration": bool(getattr(app.state, "startup_complete", False)),
"database": False,
"schema": bool(getattr(app.state, "schema_ready", False)),
"workers": False,
}
if checks["configuration"]:
try:
services.repository.health_check()
checks["database"] = True
except Exception:
checks["database"] = False
worker_state = getattr(app.state, "worker_tasks", ())
checks["workers"] = bool(worker_state) and all(
not task.done() for task in worker_state
)
ready = all(checks.values())
return JSONResponse(
status_code=(
status.HTTP_200_OK if ready else status.HTTP_503_SERVICE_UNAVAILABLE
),
content={"status": "ready" if ready else "not_ready", "checks": checks},
)
app.include_router(
create_cloud_router(
pool=pool,