Refactor all main.py

This commit is contained in:
Urtzi Alfaro
2025-09-29 13:13:12 +02:00
parent 4777e59e7a
commit befcc126b0
35 changed files with 2537 additions and 1993 deletions

View File

@@ -4,122 +4,90 @@ Recipe Service - FastAPI application
Handles recipe management, production planning, and inventory consumption tracking
"""
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.gzip import GZipMiddleware
from fastapi.responses import JSONResponse
import time
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi.middleware.gzip import GZipMiddleware
from .core.config import settings
from .core.database import db_manager
from .api import recipes
from shared.service_base import StandardFastAPIService
# Import models to register them with SQLAlchemy metadata
from .models import recipes as recipe_models
# Configure logging
logging.basicConfig(
level=getattr(logging, settings.LOG_LEVEL.upper()),
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)
class RecipesService(StandardFastAPIService):
"""Recipes Service with standardized setup"""
def __init__(self):
# Define expected database tables for health checks
recipes_expected_tables = [
'recipes', 'recipe_ingredients', 'production_batches',
'production_ingredient_consumption', 'production_schedules'
]
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan events"""
# Startup
logger.info(f"Starting {settings.SERVICE_NAME} service v{settings.SERVICE_VERSION}")
# Create database tables
try:
await db_manager.create_tables()
logger.info("Database tables created successfully")
except Exception as e:
logger.error(f"Failed to create database tables: {e}")
yield
# Shutdown
logger.info(f"Shutting down {settings.SERVICE_NAME} service")
# Create FastAPI application
app = FastAPI(
title="Recipe Management Service",
description="Comprehensive recipe management, production planning, and inventory consumption tracking for bakery operations",
version=settings.SERVICE_VERSION,
lifespan=lifespan,
docs_url="/docs" if settings.DEBUG else None,
redoc_url="/redoc" if settings.DEBUG else None,
)
# Add middleware
app.add_middleware(
CORSMiddleware,
allow_origins=settings.ALLOWED_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.add_middleware(GZipMiddleware, minimum_size=1000)
# Request timing middleware
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
"""Add processing time header to responses"""
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
# Global exception handler
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
"""Global exception handler"""
logger.error(f"Global exception on {request.url}: {exc}", exc_info=True)
return JSONResponse(
status_code=500,
content={
"detail": "Internal server error",
"error": str(exc) if settings.DEBUG else "An unexpected error occurred"
}
)
# Health check endpoint
@app.get("/health")
async def health_check():
"""Health check endpoint"""
try:
# Test database connection
health_result = await db_manager.health_check()
return {
"status": "healthy",
"service": settings.SERVICE_NAME,
"version": settings.SERVICE_VERSION,
"environment": settings.ENVIRONMENT,
"database": health_result
}
except Exception as e:
logger.error(f"Health check failed: {e}")
return JSONResponse(
status_code=503,
content={
"status": "unhealthy",
"service": settings.SERVICE_NAME,
"version": settings.SERVICE_VERSION,
"error": str(e)
}
super().__init__(
service_name="recipes-service",
app_name="Recipe Management Service",
description="Comprehensive recipe management, production planning, and inventory consumption tracking for bakery operations",
version=settings.SERVICE_VERSION,
log_level=settings.LOG_LEVEL,
cors_origins=settings.ALLOWED_ORIGINS,
api_prefix=settings.API_V1_PREFIX,
database_manager=db_manager,
expected_tables=recipes_expected_tables
)
async def on_startup(self, app: FastAPI):
"""Custom startup logic for recipes service"""
# Custom startup completed
pass
async def on_shutdown(self, app: FastAPI):
"""Custom shutdown logic for recipes service"""
# Database cleanup is handled by the base class
pass
def get_service_features(self):
"""Return recipes-specific features"""
return [
"recipe_management",
"production_planning",
"inventory_consumption_tracking",
"batch_production",
"tenant_scoped_operations"
]
def setup_custom_middleware(self):
"""Setup custom middleware for recipes service"""
# Add GZip middleware
self.app.add_middleware(GZipMiddleware, minimum_size=1000)
# Request timing middleware
@self.app.middleware("http")
async def add_process_time_header(request: Request, call_next):
"""Add processing time header to responses"""
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
# Create service instance
service = RecipesService()
# Create FastAPI app with standardized setup
app = service.create_app(
docs_url="/docs" if settings.DEBUG else None,
redoc_url="/redoc" if settings.DEBUG else None
)
# Setup standard endpoints
service.setup_standard_endpoints()
# Setup custom middleware
service.setup_custom_middleware()
# Include API routers with tenant-scoped paths
app.include_router(
@@ -129,19 +97,6 @@ app.include_router(
)
@app.get("/")
async def root():
"""Root endpoint"""
return {
"service": settings.SERVICE_NAME,
"version": settings.SERVICE_VERSION,
"status": "running",
"docs_url": "/docs" if settings.DEBUG else None
}
if __name__ == "__main__":
import uvicorn
uvicorn.run(

View File

@@ -24,6 +24,9 @@ requests==2.31.0
asyncio-mqtt==0.16.1
aiofiles==23.2.1
# Messaging
aio-pika==9.3.1
# Caching (optional)
redis==5.0.1
python-redis-cache==0.1.0
@@ -31,6 +34,7 @@ python-redis-cache==0.1.0
# Monitoring and logging
structlog==23.2.0
python-json-logger==2.0.4
prometheus-client==0.19.0
# Date/time handling
python-dateutil==2.8.2