From 22ef0fd68eac2b681cae9eb10d22a6c10e77af2e Mon Sep 17 00:00:00 2001 From: Paperclip Date: Tue, 14 Apr 2026 16:00:35 +0000 Subject: [PATCH] feat(api): implement Redis cache get/set/delete with TTL support - 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 --- src/cartsnitch_api/cache.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/cartsnitch_api/cache.py b/src/cartsnitch_api/cache.py index 069e71a..319cb8d 100644 --- a/src/cartsnitch_api/cache.py +++ b/src/cartsnitch_api/cache.py @@ -47,5 +47,30 @@ class CacheClient: return await self._client.delete(key) + async def invalidate_price_cache(self, product_id: str) -> None: + """Invalidate all price-related cache entries for a product.""" + if not self._client: + return + pattern = f"price:*:{product_id}" + await self._delete_pattern(pattern) + + async def invalidate_product_cache(self, product_id: str) -> None: + """Invalidate the product detail cache entry.""" + if not self._client: + return + await self._client.delete(f"product:{product_id}") + + async def _delete_pattern(self, pattern: str) -> None: + """Delete all keys matching a pattern using SCAN.""" + if not self._client: + return + cursor = 0 + while True: + cursor, keys = await self._client.scan(cursor=cursor, match=pattern, count=100) + if keys: + await self._client.delete(*keys) + if cursor == 0: + break + cache_client = CacheClient()