Files
bakery-ia/services/forecasting/app/main.py
2025-07-30 08:13:32 +02:00

118 lines
3.9 KiB
Python

# ================================================================
# services/forecasting/app/main.py
# ================================================================
"""
Forecasting Service Main Application
Demand prediction and forecasting service for bakery operations
"""
import structlog
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from app.core.config import settings
from app.core.database import database_manager, get_db_health
from app.api import forecasts, predictions
from app.services.messaging import setup_messaging, cleanup_messaging
from shared.monitoring.logging import setup_logging
from shared.monitoring.metrics import MetricsCollector
# Setup structured logging
setup_logging("forecasting-service", settings.LOG_LEVEL)
logger = structlog.get_logger()
# Initialize metrics collector
metrics_collector = MetricsCollector("forecasting-service")
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan manager for startup and shutdown events"""
# Startup
logger.info("Starting Forecasting Service", version="1.0.0")
try:
# Initialize database
logger.info("Initializing database connection")
await database_manager.create_tables()
logger.info("Database initialized successfully")
# Initialize messaging
logger.info("Setting up messaging")
await setup_messaging()
logger.info("Messaging initialized")
# Register custom metrics
metrics_collector.register_counter("forecasts_generated_total", "Total forecasts generated")
metrics_collector.register_counter("predictions_served_total", "Total predictions served")
metrics_collector.register_counter("prediction_errors_total", "Total prediction errors")
metrics_collector.register_histogram("forecast_processing_time_seconds", "Time to process forecast request")
metrics_collector.register_gauge("active_models_count", "Number of active models")
# Start metrics server
metrics_collector.start_metrics_server(8080)
logger.info("Forecasting Service started successfully")
yield
except Exception as e:
logger.error("Failed to start Forecasting Service", error=str(e))
raise
finally:
# Shutdown
logger.info("Shutting down Forecasting Service")
try:
await cleanup_messaging()
logger.info("Messaging cleanup completed")
except Exception as e:
logger.error("Error during messaging cleanup", error=str(e))
# Create FastAPI app with lifespan
app = FastAPI(
title="Bakery Forecasting Service",
description="AI-powered demand prediction and forecasting service for bakery operations",
version="1.0.0",
docs_url="/docs",
redoc_url="/redoc",
lifespan=lifespan
)
# CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=settings.CORS_ORIGINS_LIST,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Include API routers
app.include_router(forecasts.router, prefix="/api/v1", tags=["forecasts"])
app.include_router(predictions.router, prefix="/api/v1", tags=["predictions"])
@app.get("/health")
async def health_check():
"""Health check endpoint"""
db_health = await get_db_health()
return {
"status": "healthy" if db_health else "unhealthy",
"service": "forecasting-service",
"version": "1.0.0",
"database": "connected" if db_health else "disconnected",
"timestamp": structlog.get_logger().info("Health check requested")
}
@app.get("/metrics")
async def get_metrics():
"""Metrics endpoint for Prometheus"""
return metrics_collector.get_metrics()
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)