fix(redis): Timeouts für Async-Pool + Start-Health-Check-Log
Security Audit / Python Dependency Audit (push) Canceled after 0s
Security Audit / Node.js Dependency Audit (push) Canceled after 0s
Security Audit / Frontend Build (tsc + vite) (push) Canceled after 0s

get_async_redis() hatte keine socket_connect_timeout/socket_timeout/
max_connections – ein gehängtes Redis hätte Requests unbegrenzt
blockiert statt schnell zu failen. Zusätzlich einmaliger Ping im
Lifespan-Startup, nur zur Log-Sichtbarkeit (blockiert Boot nicht).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Ahyx6D3r7G1EuAc42nezn
This commit is contained in:
2026-09-03 01:58:33 +02:00
co-authored by Claude Sonnet 5
parent 107cba99f9
commit 9afc29a8bb
2 changed files with 24 additions and 1 deletions
+13 -1
View File
@@ -36,13 +36,25 @@ def get_async_redis():
kiosk_security._check_and_set_nonce) der Pool verwaltet Connections selbst. kiosk_security._check_and_set_nonce) der Pool verwaltet Connections selbst.
Verbindungsfehler zeigen sich erst beim ersten Call (kein Ping hier), Aufrufer Verbindungsfehler zeigen sich erst beim ersten Call (kein Ping hier), Aufrufer
müssen weiterhin except behandeln (Nonce-Fallback, TOTP-Lockout). müssen weiterhin except behandeln (Nonce-Fallback, TOTP-Lockout).
Timeouts analog zum sync-Client gesetzt, sonst würde ein gehängtes Redis
(statt eines klaren Connection-Refused) Requests unbegrenzt blockieren.
max_connections deckt Lastspitzen bei einem uvicorn-Worker ab, ohne dass
ein einzelner langsamer Client den ganzen Pool erschöpfen kann.
""" """
global _async_redis_client global _async_redis_client
if _async_redis_client is None: if _async_redis_client is None:
import redis.asyncio as aioredis import redis.asyncio as aioredis
from app.core.config import settings from app.core.config import settings
url = getattr(settings, "redis_url", "redis://localhost:6379/0") url = getattr(settings, "redis_url", "redis://localhost:6379/0")
_async_redis_client = aioredis.from_url(url, decode_responses=True) _async_redis_client = aioredis.from_url(
url,
decode_responses=True,
socket_connect_timeout=2,
socket_timeout=5,
max_connections=50,
)
log.info("Async-Redis-Pool erstellt: %s (max_connections=50)", url)
return _async_redis_client return _async_redis_client
+11
View File
@@ -52,6 +52,17 @@ async def lifespan(app: FastAPI):
from app.services.scheduler_service import start as start_scheduler from app.services.scheduler_service import start as start_scheduler
start_scheduler() start_scheduler()
# Async-Redis-Pool: einmaliger Ping beim Start, nur zur Sichtbarkeit im Log
# (Sessions/Lockouts/Nonce-Cache brauchen Redis, App startet aber auch ohne
# Fehler zeigen sich dann erst beim ersten Request, siehe get_async_redis()).
if "pytest" not in sys.modules:
from app.core.redis import get_async_redis
try:
await get_async_redis().ping()
_log.info("Async-Redis-Pool: Verbindung beim Start OK.")
except Exception as exc:
_log.warning("Async-Redis-Pool: kein Redis beim Start erreichbar (%s).", exc)
yield yield
# Shutdown # Shutdown
from app.services.scheduler_service import shutdown as shutdown_scheduler from app.services.scheduler_service import shutdown as shutdown_scheduler