demo seed change 4
This commit is contained in:
@@ -6,6 +6,8 @@ Handles routing, authentication, rate limiting, and cross-cutting concerns
|
||||
import asyncio
|
||||
import json
|
||||
import structlog
|
||||
import resource
|
||||
import os
|
||||
from fastapi import FastAPI, Request, HTTPException, Depends, WebSocket, WebSocketDisconnect
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import JSONResponse, StreamingResponse
|
||||
@@ -30,6 +32,38 @@ from shared.monitoring.metrics import MetricsCollector
|
||||
setup_logging("gateway", settings.LOG_LEVEL)
|
||||
logger = structlog.get_logger()
|
||||
|
||||
# Check file descriptor limits and warn if too low
|
||||
try:
|
||||
soft_limit, hard_limit = resource.getrlimit(resource.RLIMIT_NOFILE)
|
||||
if soft_limit < 1024:
|
||||
logger.warning(f"Low file descriptor limit detected: {soft_limit}. Gateway may experience 'too many open files' errors.")
|
||||
logger.warning(f"Recommended: Increase limit with 'ulimit -n 4096' or higher for production.")
|
||||
if soft_limit < 256:
|
||||
logger.error(f"Critical: File descriptor limit ({soft_limit}) is too low for gateway operation!")
|
||||
else:
|
||||
logger.info(f"File descriptor limit: {soft_limit} (sufficient)")
|
||||
except Exception as e:
|
||||
logger.debug(f"Could not check file descriptor limits: {e}")
|
||||
|
||||
# Check and log current working directory and permissions
|
||||
try:
|
||||
cwd = os.getcwd()
|
||||
logger.info(f"Current working directory: {cwd}")
|
||||
|
||||
# Check if we can write to common log locations
|
||||
test_locations = ["/var/log", "./logs", "."]
|
||||
for location in test_locations:
|
||||
try:
|
||||
test_file = os.path.join(location, ".gateway_permission_test")
|
||||
with open(test_file, 'w') as f:
|
||||
f.write("test")
|
||||
os.remove(test_file)
|
||||
logger.info(f"Write permission confirmed for: {location}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Cannot write to {location}: {e}")
|
||||
except Exception as e:
|
||||
logger.debug(f"Could not check directory permissions: {e}")
|
||||
|
||||
# Create FastAPI app
|
||||
app = FastAPI(
|
||||
title="Bakery Forecasting API Gateway",
|
||||
@@ -390,7 +424,18 @@ async def events_stream(
|
||||
"""Generate server-sent events from Redis pub/sub with multi-channel support"""
|
||||
pubsub = None
|
||||
try:
|
||||
# Create pubsub connection with resource monitoring
|
||||
pubsub = redis_client.pubsub()
|
||||
logger.debug(f"Created Redis pubsub connection for tenant: {tenant_id}")
|
||||
|
||||
# Monitor connection count
|
||||
try:
|
||||
connection_info = await redis_client.info('clients')
|
||||
connected_clients = connection_info.get('connected_clients', 'unknown')
|
||||
logger.debug(f"Redis connected clients: {connected_clients}")
|
||||
except Exception:
|
||||
# Don't fail if we can't get connection info
|
||||
pass
|
||||
|
||||
# Determine which channels to subscribe to
|
||||
subscription_channels = _get_subscription_channels(tenant_id, channel_filters)
|
||||
@@ -460,10 +505,24 @@ async def events_stream(
|
||||
except Exception as e:
|
||||
logger.error(f"SSE error for tenant {tenant_id}: {e}", exc_info=True)
|
||||
finally:
|
||||
if pubsub:
|
||||
await pubsub.unsubscribe()
|
||||
await pubsub.close()
|
||||
logger.info(f"SSE connection closed for tenant: {tenant_id}")
|
||||
try:
|
||||
if pubsub:
|
||||
try:
|
||||
# Unsubscribe from all channels
|
||||
await pubsub.unsubscribe()
|
||||
logger.debug(f"Unsubscribed from Redis channels for tenant: {tenant_id}")
|
||||
except Exception as unsubscribe_error:
|
||||
logger.error(f"Failed to unsubscribe Redis pubsub for tenant {tenant_id}: {unsubscribe_error}")
|
||||
|
||||
try:
|
||||
# Close pubsub connection
|
||||
await pubsub.close()
|
||||
logger.debug(f"Closed Redis pubsub connection for tenant: {tenant_id}")
|
||||
except Exception as close_error:
|
||||
logger.error(f"Failed to close Redis pubsub for tenant {tenant_id}: {close_error}")
|
||||
logger.info(f"SSE connection closed for tenant: {tenant_id}")
|
||||
except Exception as finally_error:
|
||||
logger.error(f"Error in SSE cleanup for tenant {tenant_id}: {finally_error}")
|
||||
|
||||
return StreamingResponse(
|
||||
event_generator(),
|
||||
|
||||
Reference in New Issue
Block a user