feat: Operational hardening — healthcheck, config refactor, requirements lock
- Add GET /health route (DB + Redis ping, 200/503) with Dockerfile HEALTHCHECK directive - Replace config.py stub with real pydantic BaseSettings reading directly from env vars; remove external config file mount from docker-compose - Add requirements.lock (pip freeze snapshot for bit-identical builds) - Untrack config.py globally but allow app/config.py via .gitignore negation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
42
app/routers/health.py
Normal file
42
app/routers/health.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""
|
||||
Health check endpoint for Docker orchestration.
|
||||
Verifies DB and Redis connectivity.
|
||||
"""
|
||||
import logging
|
||||
from fastapi import APIRouter
|
||||
from fastapi.responses import JSONResponse
|
||||
from sqlalchemy import text
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get('/health', tags=['Root'], include_in_schema=True)
|
||||
async def health_check():
|
||||
"""
|
||||
Checks liveness of the DB and Redis connections.
|
||||
Returns 200 if both are reachable, 503 otherwise.
|
||||
"""
|
||||
status = {'db': False, 'redis': False}
|
||||
|
||||
# --- DB check ---
|
||||
try:
|
||||
from app.lib_sql_core import engine
|
||||
with engine.connect() as conn:
|
||||
conn.execute(text('SELECT 1'))
|
||||
status['db'] = True
|
||||
except Exception as e:
|
||||
log.error(f'Health check: DB ping failed: {e}')
|
||||
|
||||
# --- Redis check ---
|
||||
try:
|
||||
from app.lib_redis_helpers import redis_client
|
||||
redis_client.ping()
|
||||
status['redis'] = True
|
||||
except Exception as e:
|
||||
log.error(f'Health check: Redis ping failed: {e}')
|
||||
|
||||
all_ok = all(status.values())
|
||||
http_status = 200 if all_ok else 503
|
||||
return JSONResponse(content={'status': 'ok' if all_ok else 'degraded', **status}, status_code=http_status)
|
||||
@@ -1,7 +1,7 @@
|
||||
from fastapi import FastAPI, Depends
|
||||
from app.routers.dependencies_v3 import DeprecationParams
|
||||
from app.routers import (
|
||||
ae_obj, aether_cfg, api_crud, api_crud_v2, api_crud_v3, api, importing, sql,
|
||||
ae_obj, aether_cfg, api_crud, api_crud_v2, api_crud_v3, api, health, importing, sql,
|
||||
account, contact, data_store,
|
||||
event, event_badge, event_badge_importing, event_badge_template,
|
||||
event_device, event_exhibit, event_exhibit_tracking, event_file, event_importing,
|
||||
@@ -17,6 +17,7 @@ def setup_routers(app: FastAPI):
|
||||
"""
|
||||
Registers all application routers with their respective prefixes and tags.
|
||||
"""
|
||||
app.include_router(health.router, tags=['Root'])
|
||||
app.include_router(ae_obj.router, prefix='/ae_obj', tags=['AE Object'])
|
||||
app.include_router(aether_cfg.router, tags=['Aether Config'])
|
||||
# app.include_router(api_crud.router, prefix='/crud', tags=['CRUD v1.2 (Legacy)'], dependencies=[Depends(DeprecationParams)])
|
||||
|
||||
Reference in New Issue
Block a user