Files
bakery-ia/services/production/app/api/internal_alert_trigger.py

89 lines
3.1 KiB
Python
Raw Normal View History

2025-12-05 20:07:01 +01:00
# services/production/app/api/internal_alert_trigger.py
"""
Internal API for triggering production alerts.
Used by demo session cloning to generate realistic production delay alerts.
2025-12-13 23:57:54 +01:00
URL Pattern: /api/v1/tenants/{tenant_id}/production/internal/alerts/trigger
This follows the tenant-scoped pattern so gateway can proxy correctly.
2025-12-05 20:07:01 +01:00
"""
from fastapi import APIRouter, HTTPException, Request, Path
from uuid import UUID
import structlog
logger = structlog.get_logger()
router = APIRouter()
2025-12-13 23:57:54 +01:00
# New URL pattern: tenant-scoped so gateway proxies to production service correctly
@router.post("/api/v1/tenants/{tenant_id}/production/internal/alerts/trigger")
2025-12-05 20:07:01 +01:00
async def trigger_production_alerts(
tenant_id: UUID = Path(..., description="Tenant ID to check production for"),
request: Request = None
) -> dict:
"""
2025-12-13 23:57:54 +01:00
Trigger comprehensive production alert checks for a specific tenant (internal use only).
2025-12-05 20:07:01 +01:00
This endpoint is called by the demo session cloning process after production
2025-12-13 23:57:54 +01:00
batches are seeded to generate realistic production alerts including:
- Production delays
- Equipment maintenance alerts
- Batch start delays
2025-12-05 20:07:01 +01:00
Security: Protected by X-Internal-Service header check.
"""
try:
# Verify internal service header
if not request or request.headers.get("X-Internal-Service") not in ["demo-session", "internal"]:
logger.warning("Unauthorized internal API call", tenant_id=str(tenant_id))
raise HTTPException(
status_code=403,
detail="This endpoint is for internal service use only"
)
2025-12-13 23:57:54 +01:00
# Get production scheduler from app state
production_scheduler = getattr(request.app.state, 'production_scheduler', None)
2025-12-05 20:07:01 +01:00
2025-12-13 23:57:54 +01:00
if not production_scheduler:
logger.error("Production scheduler not initialized")
2025-12-05 20:07:01 +01:00
raise HTTPException(
status_code=500,
2025-12-13 23:57:54 +01:00
detail="Production scheduler not available"
2025-12-05 20:07:01 +01:00
)
2025-12-13 23:57:54 +01:00
# Trigger comprehensive production alert checks for the specific tenant
logger.info("Triggering comprehensive production alert checks", tenant_id=str(tenant_id))
2025-12-05 20:07:01 +01:00
2025-12-13 23:57:54 +01:00
# Call the scheduler's manual trigger method
result = await production_scheduler.trigger_manual_check(tenant_id)
2025-12-05 20:07:01 +01:00
2025-12-13 23:57:54 +01:00
if result.get("success", False):
logger.info(
"Production alert checks completed successfully",
tenant_id=str(tenant_id),
alerts_generated=result.get("alerts_generated", 0)
)
else:
logger.error(
"Production alert checks failed",
tenant_id=str(tenant_id),
error=result.get("error", "Unknown error")
)
2025-12-05 20:07:01 +01:00
2025-12-13 23:57:54 +01:00
return result
2025-12-05 20:07:01 +01:00
except HTTPException:
raise
except Exception as e:
logger.error(
"Error triggering production alerts",
tenant_id=str(tenant_id),
error=str(e),
exc_info=True
)
raise HTTPException(
status_code=500,
detail=f"Failed to trigger production alerts: {str(e)}"
)