Spaces:
Running
Running
| import os | |
| import motor.motor_asyncio | |
| import redis.asyncio as redis | |
| from redis.exceptions import RedisError | |
| from dotenv import load_dotenv | |
| import logging | |
| from datetime import datetime | |
| from app.config.config import settings, validate_configuration | |
| # Configure logging | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", | |
| ) | |
| logger = logging.getLogger(__name__) | |
| # Load environment variables from .env file (fallback) | |
| load_dotenv() | |
| # Validate configuration on import | |
| try: | |
| validate_configuration() | |
| except ValueError as e: | |
| logger.error(f"Configuration validation failed: {e}") | |
| # In production, we want to fail fast if configuration is missing | |
| raise | |
| # MongoDB configuration using settings | |
| MONGO_URI = settings.MONGO_URI | |
| DB_NAME = settings.DB_NAME | |
| # Redis configuration using settings | |
| CACHE_URI = settings.CACHE_URI | |
| CACHE_K = settings.CACHE_K | |
| # Parse Redis host and port safely | |
| try: | |
| if ':' in CACHE_URI: | |
| CACHE_HOST, CACHE_PORT = CACHE_URI.split(":", 1) | |
| CACHE_PORT = int(CACHE_PORT) | |
| else: | |
| CACHE_HOST = CACHE_URI | |
| CACHE_PORT = 6379 # Default Redis port | |
| except ValueError as e: | |
| logger.error(f"Invalid Redis URI format: {CACHE_URI}") | |
| raise ValueError(f"Invalid Redis configuration: {e}") | |
| # Initialize MongoDB client with secure connection | |
| try: | |
| # Ensure SSL is enabled for production | |
| if not MONGO_URI.startswith('mongodb://localhost') and 'ssl=true' not in MONGO_URI: | |
| logger.warning("MongoDB connection may not be using SSL. Consider enabling SSL for production.") | |
| client = motor.motor_asyncio.AsyncIOMotorClient( | |
| MONGO_URI, | |
| serverSelectionTimeoutMS=5000, # 5 second timeout | |
| connectTimeoutMS=10000, # 10 second connection timeout | |
| maxPoolSize=50, # Connection pool size | |
| retryWrites=True # Enable retryable writes | |
| ) | |
| db = client[DB_NAME] | |
| logger.info(f"β MongoDB client initialized for database: {DB_NAME}") | |
| except Exception as e: | |
| logger.error(f"β Failed to initialize MongoDB client: {e}") | |
| # Don't log the full URI to avoid credential exposure | |
| logger.error("Please check your MongoDB configuration.") | |
| raise | |
| # Initialize Redis client with secure connection | |
| try: | |
| redis_client = redis.Redis( | |
| host=CACHE_HOST, | |
| port=CACHE_PORT, | |
| username="default", | |
| password=CACHE_K, | |
| decode_responses=True, | |
| socket_timeout=5, # 5 second socket timeout | |
| socket_connect_timeout=5, # 5 second connection timeout | |
| retry_on_timeout=True, | |
| health_check_interval=30 # Health check every 30 seconds | |
| ) | |
| logger.info("β Redis client initialized") | |
| except Exception as e: | |
| logger.error(f"β Failed to initialize Redis client: {e}") | |
| # Don't log credentials | |
| logger.error("Please check your Redis configuration.") | |
| raise | |
| # Connection health check functions | |
| async def check_mongodb_health() -> bool: | |
| """Check MongoDB connection health""" | |
| try: | |
| await client.admin.command('ping') | |
| return True | |
| except Exception as e: | |
| logger.error(f"MongoDB health check failed: {e}") | |
| return False | |
| async def check_redis_health() -> bool: | |
| """Check Redis connection health""" | |
| try: | |
| await redis_client.ping() | |
| return True | |
| except Exception as e: | |
| logger.error(f"Redis health check failed: {e}") | |
| return False | |
| async def get_database_status() -> dict: | |
| """Get database connection status""" | |
| return { | |
| "mongodb": await check_mongodb_health(), | |
| "redis": await check_redis_health(), | |
| "timestamp": datetime.utcnow().isoformat() | |
| } | |
| # Graceful shutdown functions | |
| async def close_database_connections(): | |
| """Close all database connections gracefully""" | |
| try: | |
| if client: | |
| client.close() | |
| logger.info("MongoDB connection closed") | |
| except Exception as e: | |
| logger.error(f"Error closing MongoDB connection: {e}") | |
| try: | |
| if redis_client: | |
| await redis_client.close() | |
| logger.info("Redis connection closed") | |
| except Exception as e: | |
| logger.error(f"Error closing Redis connection: {e}") | |