<< All versions
Skill v1.0.0
currentAutomated scan100/100izangi2714/claude-code-python-stack/redis-patterns
──Details
PublishedSeptember 28, 2026 at 09:17 AM
Content Hashsha256:b3a3d2de4b2c9e1e...
Git SHA
──Files
Files (1 file, 6.3 KB)
SKILL.md6.3 KBactive
SKILL.md · 255 lines · 6.3 KB
version: "1.0.0" name: redis-patterns description: Redis patterns for Python — caching, sessions, pub/sub, rate limiting, distributed locks, and integration with Django/FastAPI. origin: custom
Redis Patterns for Python
Redis usage patterns for caching, sessions, queues, and distributed systems.
When to Activate
- Implementing caching layer
- Setting up session storage
- Building pub/sub messaging
- Implementing rate limiting
- Using distributed locks
Connection Setup
redis-py (Sync)
python
import redispool = redis.ConnectionPool(host="localhost", port=6379, db=0,max_connections=20,decode_responses=True,)r = redis.Redis(connection_pool=pool)
redis-py (Async)
python
import redis.asyncio as aioredispool = aioredis.ConnectionPool.from_url("redis://localhost:6379/0",max_connections=20,decode_responses=True,)redis_client = aioredis.Redis(connection_pool=pool)# Usageasync def get_cached(key: str) -> str | None:return await redis_client.get(key)
Caching Patterns
Simple Cache
python
import jsonfrom datetime import timedeltaasync def get_user(user_id: int) -> dict:cache_key = f"user:{user_id}"# Try cache firstcached = await redis_client.get(cache_key)if cached:return json.loads(cached)# Fetch from DBuser = await db.get_user(user_id)if user:await redis_client.setex(cache_key, timedelta(minutes=15), json.dumps(user))return user
Cache Invalidation
python
async def update_user(user_id: int, data: dict) -> dict:user = await db.update_user(user_id, data)# Invalidate cacheawait redis_client.delete(f"user:{user_id}")# Invalidate related cachesawait redis_client.delete(f"user_list:page:*")return user
Cache-Aside with Decorator
python
import functoolsimport hashlibdef cached(ttl: int = 300, prefix: str = "cache"):def decorator(func):@functools.wraps(func)async def wrapper(*args, **kwargs):key_data = f"{func.__name__}:{args}:{sorted(kwargs.items())}"cache_key = f"{prefix}:{hashlib.md5(key_data.encode()).hexdigest()}"cached_result = await redis_client.get(cache_key)if cached_result:return json.loads(cached_result)result = await func(*args, **kwargs)await redis_client.setex(cache_key, ttl, json.dumps(result, default=str))return resultreturn wrapperreturn decorator@cached(ttl=600, prefix="products")async def get_products(category: str, page: int = 1) -> list[dict]:return await db.query_products(category=category, page=page)
Rate Limiting
Sliding Window
python
import timeasync def is_rate_limited(user_id: str, limit: int = 100, window: int = 60) -> bool:key = f"rate_limit:{user_id}"now = time.time()pipe = redis_client.pipeline()pipe.zremrangebyscore(key, 0, now - window) # Remove old entriespipe.zadd(key, {str(now): now}) # Add current requestpipe.zcard(key) # Count requests in windowpipe.expire(key, window) # Set expiryresults = await pipe.execute()request_count = results[2]return request_count > limit
Token Bucket
python
async def check_rate_limit(key: str, max_tokens: int = 10, refill_rate: float = 1.0) -> bool:"""Token bucket rate limiter. Returns True if request is allowed."""now = time.time()pipe = redis_client.pipeline()pipe.hgetall(key)result = await pipe.execute()data = result[0]tokens = float(data.get("tokens", max_tokens))last_refill = float(data.get("last_refill", now))# Refill tokenselapsed = now - last_refilltokens = min(max_tokens, tokens + elapsed * refill_rate)if tokens >= 1:tokens -= 1await redis_client.hset(key, mapping={"tokens": tokens, "last_refill": now})await redis_client.expire(key, int(max_tokens / refill_rate) + 1)return Truereturn False
Distributed Lock
python
import uuidclass RedisLock:def __init__(self, redis_client, name: str, timeout: int = 10):self.redis = redis_clientself.name = f"lock:{name}"self.timeout = timeoutself.token = str(uuid.uuid4())async def __aenter__(self):acquired = await self.redis.set(self.name, self.token, nx=True, ex=self.timeout)if not acquired:raise RuntimeError(f"Could not acquire lock: {self.name}")return selfasync def __aexit__(self, *args):# Only release if we own the locklua_script = """if redis.call("get", KEYS[1]) == ARGV[1] thenreturn redis.call("del", KEYS[1])elsereturn 0end"""await self.redis.eval(lua_script, 1, self.name, self.token)# Usageasync def process_order(order_id: int):async with RedisLock(redis_client, f"order:{order_id}", timeout=30):# Only one worker processes this order at a timeawait do_process(order_id)
Pub/Sub
python
# Publisherasync def publish_event(channel: str, event: dict):await redis_client.publish(channel, json.dumps(event))# Subscriberasync def subscribe_events(channel: str):pubsub = redis_client.pubsub()await pubsub.subscribe(channel)async for message in pubsub.listen():if message["type"] == "message":event = json.loads(message["data"])await handle_event(event)
Django Integration
python
# settings.pyCACHES = {"default": {"BACKEND": "django.core.cache.backends.redis.RedisCache","LOCATION": "redis://localhost:6379/0","OPTIONS": {"pool_class": "redis.BlockingConnectionPool","max_connections": 50,},}}SESSION_ENGINE = "django.contrib.sessions.backends.cache"SESSION_CACHE_ALIAS = "default"
Quick Reference
| Pattern | Use Case | |
|---|---|---|
GET/SET/SETEX | Simple key-value caching | |
HSET/HGETALL | Structured data (hash maps) | |
ZADD/ZRANGEBYSCORE | Rate limiting (sorted sets) | |
SET NX EX | Distributed locks | |
PUBLISH/SUBSCRIBE | Event broadcasting | |
LPUSH/BRPOP | Task queues | |
Pipeline | Batch operations | |
Lua scripts | Atomic operations |