# services/external/app/main.py """ External Service Main Application """ from fastapi import FastAPI from app.core.config import settings from app.core.database import database_manager from app.services.messaging import setup_messaging, cleanup_messaging from shared.service_base import StandardFastAPIService # Include routers from app.api.weather import router as weather_router from app.api.traffic import router as traffic_router class ExternalService(StandardFastAPIService): """External Data Service with standardized setup""" def __init__(self): # Define expected database tables for health checks external_expected_tables = [ 'weather_data', 'weather_forecasts', 'traffic_data', 'traffic_measurement_points', 'traffic_background_jobs' ] # Define custom API checks async def check_weather_api(): """Check weather API configuration""" try: return bool(settings.AEMET_API_KEY) except Exception as e: self.logger.error("Weather API check failed", error=str(e)) return False async def check_traffic_api(): """Check traffic API configuration""" try: return bool(settings.MADRID_OPENDATA_API_KEY) except Exception as e: self.logger.error("Traffic API check failed", error=str(e)) return False # Define custom metrics for external service external_custom_metrics = { "weather_api_calls_total": { "type": "counter", "description": "Total weather API calls" }, "weather_api_success_total": { "type": "counter", "description": "Successful weather API calls" }, "weather_api_failures_total": { "type": "counter", "description": "Failed weather API calls" }, "traffic_api_calls_total": { "type": "counter", "description": "Total traffic API calls" }, "traffic_api_success_total": { "type": "counter", "description": "Successful traffic API calls" }, "traffic_api_failures_total": { "type": "counter", "description": "Failed traffic API calls" }, "data_collection_jobs_total": { "type": "counter", "description": "Data collection jobs" }, "data_records_stored_total": { "type": "counter", "description": "Data records stored" }, "data_quality_issues_total": { "type": "counter", "description": "Data quality issues detected" }, "weather_api_duration_seconds": { "type": "histogram", "description": "Weather API call duration" }, "traffic_api_duration_seconds": { "type": "histogram", "description": "Traffic API call duration" }, "data_collection_duration_seconds": { "type": "histogram", "description": "Data collection job duration" }, "data_processing_duration_seconds": { "type": "histogram", "description": "Data processing duration" } } super().__init__( service_name="external-service", app_name="Bakery External Data Service", description="External data collection service for weather, traffic, and events data", version="1.0.0", log_level=settings.LOG_LEVEL, cors_origins=settings.CORS_ORIGINS, api_prefix="/api/v1", database_manager=database_manager, expected_tables=external_expected_tables, custom_health_checks={ "weather_api": check_weather_api, "traffic_api": check_traffic_api }, custom_metrics=external_custom_metrics, enable_messaging=True ) async def _setup_messaging(self): """Setup messaging for external service""" await setup_messaging() self.logger.info("External service messaging initialized") async def _cleanup_messaging(self): """Cleanup messaging for external service""" await cleanup_messaging() async def on_startup(self, app: FastAPI): """Custom startup logic for external service""" pass async def on_shutdown(self, app: FastAPI): """Custom shutdown logic for external service""" # Database cleanup is handled by the base class pass def get_service_features(self): """Return external-specific features""" return [ "weather_data_collection", "traffic_data_collection", "aemet_integration", "madrid_opendata_integration", "data_quality_monitoring", "scheduled_collection_jobs", "external_api_monitoring" ] # Create service instance service = ExternalService() # Create FastAPI app with standardized setup app = service.create_app() # Setup standard endpoints service.setup_standard_endpoints() # Include routers service.add_router(weather_router, tags=["weather"]) service.add_router(traffic_router, tags=["traffic"])