117 lines
3.8 KiB
Python
117 lines
3.8 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_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/forecasts", tags=["forecasts"])
|
|
app.include_router(predictions.router, prefix="/api/v1/predictions", 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)
|
|
|