""" Service discovery for API Gateway """ import logging import httpx from typing import Optional, Dict import json from app.core.config import settings logger = logging.getLogger(__name__) class ServiceDiscovery: """Service discovery client""" def __init__(self): self.consul_url = settings.CONSUL_URL if hasattr(settings, 'CONSUL_URL') else None self.service_cache: Dict[str, str] = {} async def get_service_url(self, service_name: str) -> Optional[str]: """Get service URL from service discovery""" # Return cached URL if available if service_name in self.service_cache: return self.service_cache[service_name] # Try Consul if enabled if self.consul_url and getattr(settings, 'ENABLE_SERVICE_DISCOVERY', False): try: url = await self._get_from_consul(service_name) if url: self.service_cache[service_name] = url return url except Exception as e: logger.warning(f"Failed to get {service_name} from Consul: {e}") # Fall back to environment variables return self._get_from_env(service_name) async def _get_from_consul(self, service_name: str) -> Optional[str]: """Get service URL from Consul""" try: async with httpx.AsyncClient(timeout=5.0) as client: response = await client.get( f"{self.consul_url}/v1/health/service/{service_name}?passing=true" ) if response.status_code == 200: services = response.json() if services: service = services[0] address = service['Service']['Address'] port = service['Service']['Port'] return f"http://{address}:{port}" except Exception as e: logger.error(f"Consul query failed: {e}") return None def _get_from_env(self, service_name: str) -> Optional[str]: """Get service URL from environment variables""" env_var = f"{service_name.upper().replace('-', '_')}_SERVICE_URL" return getattr(settings, env_var, None)