Three CI-blocking issues on dev branch (also present on uat, fixed in 2b20946):
1. tests/conftest.py — remove extra blank line (ruff format).
2. src/cartsnitch_api/middleware/rate_limit.py — delete duplicate
_public_limiter/_auth_limiter/_auth_strict_limiter forward-decl block
(the second occurrence; mypy no-redef).
3. src/cartsnitch_api/cache.py:38 — annotate
value: str | bytes | None so mypy doesn't widen redis client return
to Any (no-any-return).
Verified: ruff check . && ruff format --check . && mypy src/cartsnitch_api
all pass.
Sibling of CAR-1330 (which fixes uat directly). Heals dev so future
dev → uat promotions stay green.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
QA review of PR #39 (CAR-1121) identified three blocking issues; this
commit addresses all three plus the typecheck errors flagged as CI RED.
CAR-1077 (PR #39) changes:
- database.py: add pool_timeout=30 so the engine fails fast when the
connection pool is exhausted (defends against the "server closed
connection unexpectedly" pod failures).
- routes/health.py: /health now calls SELECT 1 through Depends(get_db)
and raises HTTPException(503) when the database is unreachable, so
Kubernetes readiness probes can correctly mark the pod unhealthy and
stop routing traffic to it. Logs the failure at exception level for
observability.
- Drop .mcp.json from this PR (root-level MCP server config, not
related to the pool fix; tracked separately).
CI typecheck fixes (pre-existing on dev, were failing mypy on PR #39):
- auth/passwords.py: cast bcrypt return values so mypy doesn't widen
to Any.
- config.py: silence the false-positive call-arg on Settings() — the
three required fields are populated from the environment by
pydantic-settings at runtime.
- cache.py: coerce the bytes/str union returned by the redis client
to the documented str | None return type.
- middleware/rate_limit.py: annotate the three module-level limiters
with the RateLimitBackend protocol, cast the redis zrange score to
float before arithmetic, and add max_requests/window_seconds to the
protocol so the response-header builder can read them.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Add async Redis client using redis-py with connection pooling
- Implement get/set/delete with graceful degradation when unavailable
- Add TTL support (default 300s) via SETEX
- Add cache invalidation hooks for price and product changes
- Use pattern-based SCAN for bulk invalidation
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Add connection pool config to SQLAlchemy async engine (pool_size=10, max_overflow=20, pool_pre_ping, pool_recycle)
- Implement Redis connection pool in CacheClient with initialize/close lifecycle
- Wire lifespan startup/shutdown to initialize and dispose pools
- Add dispose_engine() for graceful DB pool cleanup on shutdown
Closes CAR-550
Co-Authored-By: Paperclip <noreply@paperclip.ing>