Files
routesapi/app/routes/health.py

98 lines
2.9 KiB
Python

"""Professional health check endpoints."""
import time
import logging
import sys
from typing import Optional
from datetime import datetime
from fastapi import APIRouter, Request
from pydantic import BaseModel, Field
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/v1/health", tags=["Health"])
start_time = time.time()
class HealthResponse(BaseModel):
"""Health check response model."""
status: str = Field(..., description="Service status")
uptime_seconds: float = Field(..., description="Service uptime in seconds")
version: str = Field("2.0.0", description="API version")
timestamp: str = Field(..., description="Health check timestamp (ISO 8601)")
request_id: Optional[str] = Field(None, description="Request ID for tracing")
@router.get("/", response_model=HealthResponse)
async def health_check(request: Request):
"""
Health check endpoint.
Returns the current health status of the API service including:
- Service status (healthy/unhealthy)
- Uptime in seconds
- API version
- Timestamp
"""
try:
uptime = time.time() - start_time
request_id = getattr(request.state, "request_id", None)
return HealthResponse(
status="healthy",
uptime_seconds=round(uptime, 2),
version="2.0.0",
timestamp=datetime.utcnow().isoformat() + "Z",
request_id=request_id
)
except Exception as e:
logger.error(f"Health check failed: {e}", exc_info=True)
request_id = getattr(request.state, "request_id", None)
return HealthResponse(
status="unhealthy",
uptime_seconds=0.0,
version="2.0.0",
timestamp=datetime.utcnow().isoformat() + "Z",
request_id=request_id
)
@router.get("/ready")
async def readiness_check(request: Request):
"""
Readiness check endpoint for load balancers.
Returns 200 if the service is ready to accept requests.
"""
try:
# Check if critical services are available
# Add your service health checks here
return {
"status": "ready",
"timestamp": datetime.utcnow().isoformat() + "Z",
"request_id": getattr(request.state, "request_id", None)
}
except Exception as e:
logger.error(f"Readiness check failed: {e}")
return {
"status": "not_ready",
"timestamp": datetime.utcnow().isoformat() + "Z",
"request_id": getattr(request.state, "request_id", None)
}
@router.get("/live")
async def liveness_check(request: Request):
"""
Liveness check endpoint for container orchestration.
Returns 200 if the service is alive.
"""
return {
"status": "alive",
"timestamp": datetime.utcnow().isoformat() + "Z",
"request_id": getattr(request.state, "request_id", None)
}