Add forecasting service

This commit is contained in:
Urtzi Alfaro
2025-07-21 19:48:56 +02:00
parent 2d85dd3e9e
commit 0e7ca10a29
24 changed files with 2937 additions and 179 deletions

View File

@@ -1,61 +1,116 @@
# ================================================================
# services/forecasting/app/main.py
# ================================================================
"""
uLuforecasting Service
Forecasting Service Main Application
Demand prediction and forecasting service for bakery operations
"""
import structlog
from fastapi import FastAPI
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
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 logging
setup_logging("forecasting-service", "INFO")
# Setup structured logging
setup_logging("forecasting-service", settings.LOG_LEVEL)
logger = structlog.get_logger()
# Create FastAPI app
app = FastAPI(
title="uLuforecasting Service",
description="uLuforecasting service for bakery forecasting",
version="1.0.0"
)
# 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=["*"],
allow_origins=settings.CORS_ORIGINS_LIST,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.on_event("startup")
async def startup_event():
"""Application startup"""
logger.info("Starting uLuforecasting Service")
# Create database tables
await database_manager.create_tables()
# Start metrics server
metrics_collector.start_metrics_server(8080)
logger.info("uLuforecasting Service started successfully")
# 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",
"status": "healthy" if db_health else "unhealthy",
"service": "forecasting-service",
"version": "1.0.0"
"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.generate_latest()
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)