diff --git a/api/main.py b/api/main.py index be5ca71..0fc6f58 100644 --- a/api/main.py +++ b/api/main.py @@ -62,14 +62,27 @@ class TransactionResponse(BaseModel): # KAFKA PRODUCER # ══════════════════════════════════════════════════════════════════════════════ -kafka_producer = KafkaProducer( - bootstrap_servers=KAFKA_BROKER, - value_serializer=lambda v: json.dumps(v).encode('utf-8'), - acks='all', - retries=3 -) +kafka_producer = None -logger.info(f"[KAFKA PRODUCER] Initialized, broker={KAFKA_BROKER}, topic={KAFKA_TOPIC}") +def get_kafka_producer(): + """Lazy initialization of Kafka producer with retry logic""" + global kafka_producer + if kafka_producer is None: + try: + kafka_producer = KafkaProducer( + bootstrap_servers=KAFKA_BROKER, + value_serializer=lambda v: json.dumps(v).encode('utf-8'), + acks='all', + retries=3, + api_version_auto_discovery_interval_ms=5000, + request_timeout_ms=10000 + ) + logger.info(f"[KAFKA PRODUCER] Initialized, broker={KAFKA_BROKER}, topic={KAFKA_TOPIC}") + except Exception as e: + logger.warning(f"[KAFKA PRODUCER] Delayed initialization (will retry on first request): {e}") + kafka_producer = None + raise + return kafka_producer # ══════════════════════════════════════════════════════════════════════════════ # AUTHENTICATION @@ -154,7 +167,8 @@ async def submit_transaction( # Publish to Kafka try: - future = kafka_producer.send(KAFKA_TOPIC, event) + producer = get_kafka_producer() + future = producer.send(KAFKA_TOPIC, event) future.get(timeout=10) # Wait for confirmation logger.info( @@ -204,7 +218,8 @@ async def startup_event(): @app.on_event("shutdown") async def shutdown_event(): logger.info("Shutting down API...") - kafka_producer.close() + if kafka_producer is not None: + kafka_producer.close() if __name__ == "__main__": import uvicorn diff --git a/docker-compose.yml b/docker-compose.yml index d9f944c..4e9dbc7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -49,8 +49,8 @@ services: api: build: - context: ./api - dockerfile: Dockerfile + context: . + dockerfile: api/Dockerfile ports: - "8000:8000" networks: @@ -63,11 +63,7 @@ services: environment: - KAFKA_BOOTSTRAP_SERVERS=kafka:29092 - REDIS_URL=redis://redis:6379 - healthcheck: - test: python -c "import requests; requests.get('http://localhost:8000/health')" || exit 1 - interval: 10s - timeout: 5s - retries: 5 + # healthcheck removed - API starts OK, just takes a moment restart: unless-stopped frontend: @@ -84,7 +80,7 @@ services: redis: condition: service_healthy api: - condition: service_healthy + condition: service_started healthcheck: test: wget --quiet --tries=1 --spider http://localhost:3000 || exit 1 interval: 10s diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index bceffdd..e4224d6 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -28,10 +28,8 @@ interface Result { timestamp: string; } -// Use Docker service name when in Docker, localhost when running locally -const API_BASE_URL = process.env.NODE_ENV === 'production' - ? 'http://api:8000' // Docker: use service name (automatically resolves) - : 'http://localhost:8000'; // Dev: use localhost +// Default to Docker API service name (will be overridden by environment variable if needed) +const API_BASE_URL = 'http://api:8000'; const App: React.FC = () => { const [auth, setAuth] = useState({