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
|
|
|
|
2026-01-12 22:15:11 +01:00
|
|
|
Security: Protected by x-internal-service header check.
|
2025-12-05 20:07:01 +01:00
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
# Verify internal service header
|
2026-01-12 22:15:11 +01:00
|
|
|
if not request or request.headers.get("x-internal-service") not in ["demo-session", "internal"]:
|
2025-12-05 20:07:01 +01:00
|
|
|
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)}"
|
|
|
|
|
)
|