Coverage for src\utility\rediss.py: 100%
39 statements
« prev ^ index » next coverage.py v7.10.1, created at 2025-10-19 21:13 +0800
« prev ^ index » next coverage.py v7.10.1, created at 2025-10-19 21:13 +0800
1from collections.abc import AsyncIterator
2from contextlib import asynccontextmanager
3from fastapi import FastAPI
4from fastapi_cache import FastAPICache
5from fastapi_cache.backends.redis import RedisBackend
6from fastapi_cache.decorator import cache #noqa: F401
7from fastapi_cache.types import Backend
8from redis import asyncio as aioredis
9from redis.exceptions import ConnectionError
10from src.utility.config import Config
11from src.utility.lib import Logger
12from typing import Optional, Tuple, override
15class NoOpBackend(Backend):
16 @override
17 async def get(self, key: str) -> Optional[bytes]: # pragma: no cover
18 return None
20 @override
21 async def set(self, key: str, value: bytes, expire: Optional[int] = None) -> None: # pragma: no cover
22 pass
24 @override
25 async def clear(self, namespace: Optional[str] = None, key: Optional[str] = None) -> int: # pragma: no cover
26 return 0
28 @override
29 async def get_with_ttl(self, key: str) -> Tuple[int, Optional[bytes]]: # pragma: no cover
30 return 0, None
33class SafeRedisBackend(RedisBackend):
34 @override
35 async def get_with_ttl(self, key: str) -> Tuple[int, Optional[bytes]]: # pragma: no cover
36 async with self.redis.pipeline(transaction=False) as pipe: # transaction is set to False to prevent this Redis error: "Error in get_with_ttl: unknown command 'EXEC'"
37 return await pipe.ttl(key).get(key).execute()
40def lifespan_factory(enable_cache: bool, flush_cache: bool):
41 @asynccontextmanager
42 async def lifespan(_: FastAPI) -> AsyncIterator[None]:
43 FastAPICache._init = False
45 if not enable_cache:
46 FastAPICache.init(backend=NoOpBackend())
47 Logger.warn("Redis caching disabled - configuration.")
49 yield
50 return
52 try:
53 redis = aioredis.from_url(
54 url=Config.REDIS_SCHEME,
55 host=Config.REDIS_HOST,
56 port=Config.REDIS_PORT,
57 username=Config.REDIS_USERNAME,
58 password=Config.REDIS_PASSWORD
59 )
60 await redis.ping()
62 if flush_cache:
63 await redis.flushall()
64 Logger.warn("Redis cache flushed on startup.")
66 FastAPICache.init(backend=SafeRedisBackend(redis), prefix="fastapi-cache")
67 Logger.info("Redis caching enabled.")
69 except ConnectionError:
70 FastAPICache.init(backend=NoOpBackend())
71 Logger.exception("Redis caching disabled - connection issue.")
73 except Exception:
74 FastAPICache.init(backend=NoOpBackend())
75 Logger.exception("Redis caching disabled - unexpected error.")
77 yield
79 return lifespan