Files
2026-01-19 11:55:17 +01:00

127 lines
4.9 KiB
Python

"""
Distribution Service Main Application
"""
from fastapi import FastAPI
from sqlalchemy import text
from app.core.config import settings
from app.core.database import database_manager
from app.api.routes import router as distribution_router
from app.api.shipments import router as shipments_router
from app.api.internal_demo import router as internal_demo_router
from app.api.vrp_optimization import router as vrp_optimization_router
from shared.service_base import StandardFastAPIService
class DistributionService(StandardFastAPIService):
"""Distribution Service with standardized setup"""
async def on_startup(self, app):
"""Custom startup logic including migration verification"""
await self.verify_migrations()
await super().on_startup(app)
async def verify_migrations(self):
"""Verify database schema matches the latest migrations."""
try:
async with self.database_manager.get_session() as session:
# Check if alembic_version table exists
result = await session.execute(text("""
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = 'alembic_version'
)
"""))
table_exists = result.scalar()
if table_exists:
# If table exists, check the version
result = await session.execute(text("SELECT version_num FROM alembic_version"))
version = result.scalar()
self.logger.info(f"Migration verification successful: {version}")
else:
# If table doesn't exist, migrations might not have run yet
# This is OK - the migration job should create it
self.logger.warning("alembic_version table does not exist yet - migrations may not have run")
except Exception as e:
self.logger.warning(f"Migration verification failed (this may be expected during initial setup): {e}")
def __init__(self):
# Define expected database tables for health checks
# Must match tables created in migrations/versions/001_initial_schema.py
distribution_expected_tables = [
'delivery_routes', 'shipments', 'delivery_schedules'
]
# Define custom metrics for distribution service
distribution_custom_metrics = {
"routes_generated_total": {
"type": "counter",
"description": "Total delivery routes generated"
},
"shipments_processed_total": {
"type": "counter",
"description": "Total shipments processed"
},
"route_optimization_time_seconds": {
"type": "histogram",
"description": "Time to optimize delivery routes"
},
"shipment_processing_time_seconds": {
"type": "histogram",
"description": "Time to process shipment request"
},
"delivery_completion_rate": {
"type": "counter",
"description": "Delivery completion rate by status",
"labels": ["status"]
}
}
super().__init__(
service_name="distribution-service",
app_name="Distribution Service",
description="Distribution and logistics service for enterprise tier bakery management",
version="1.0.0",
log_level=settings.LOG_LEVEL,
api_prefix="", # Empty because RouteBuilder already includes /api/v1
database_manager=database_manager,
expected_tables=distribution_expected_tables,
custom_metrics=distribution_custom_metrics
)
async def on_shutdown(self, app: FastAPI):
"""Custom shutdown logic for distribution service"""
self.logger.info("Distribution Service shutdown complete")
def get_service_features(self):
"""Return distribution-specific features"""
return [
"delivery_route_optimization",
"shipment_tracking",
"vehicle_assignment",
"distribution_planning",
"delivery_point_management"
]
# Create service instance
service = DistributionService()
# Create FastAPI app with standardized setup
app = service.create_app(
docs_url="/docs",
redoc_url="/redoc"
)
# Setup standard endpoints
service.setup_standard_endpoints()
# Include routers with specific configurations
# Note: Routes now use RouteBuilder which includes full paths, so no prefix needed
service.add_router(distribution_router, tags=["distribution"])
service.add_router(shipments_router, tags=["shipments"])
service.add_router(internal_demo_router, tags=["internal-demo"])
service.add_router(vrp_optimization_router, tags=["vrp-optimization"])