"""Async lifespan helper to initialize an asyncio Redis client and attach to app.state.redis. This separates the async redis client lifecycle from synchronous redis_client/redis_manager modules. """ import os from contextlib import asynccontextmanager import redis.asyncio as aioredis import redis as redis_sync from fastapi import FastAPI import logging logger = logging.getLogger("app.redis") @asynccontextmanager async def lifespan(app: FastAPI): redis_url = os.getenv("REDIS_URL") redis_host = os.getenv("REDIS_HOST", "127.0.0.1") redis_port = int(os.getenv("REDIS_PORT", "6379")) redis_db = int(os.getenv("REDIS_DB", "0")) redis_password = os.getenv("REDIS_PASSWORD", None) if redis_url: async_client = aioredis.from_url(redis_url, decode_responses=True) sync_client = redis_sync.from_url(redis_url, decode_responses=True) else: client = redis.Redis(host=redis_host, port=redis_port, db=redis_db, password=redis_password, decode_responses=True) try: # Verify connectivity for both clients await async_client.ping() try: sync_client.ping() except Exception: logger.warning("Sync Redis ping failed during startup", exc_info=True) app.state.redis = async_client app.state.redis_sync = sync_client logger.info("Redis clients initialized and attached to app.state.redis (async) and app.state.redis_sync (sync) (host=%s port=%s db=%s)", redis_host, redis_port, redis_db) except Exception as e: logger.error("Failed to initialize Redis clients: %s", e, exc_info=True) app.state.redis = None app.state.redis_sync = None try: yield finally: try: if getattr(app.state, "redis", None) is not None: await app.state.redis.close() logger.info("Async Redis client closed on shutdown") except Exception: logger.error("Error closing async Redis client", exc_info=True) # Close sync client try: if getattr(app.state, "redis_sync", None) is not None: try: app.state.redis_sync.close() except Exception: try: app.state.redis_sync.connection_pool.disconnect() except Exception: pass logger.info("Sync Redis client closed on shutdown") except Exception: logger.error("Error closing sync Redis client", exc_info=True)