---
name: ecc-redis-patterns
description: Redis data structure patterns, caching strategies, distributed locks, rate limiting, pub/sub, and connection management for production applications.
---

# Redis Patterns

Redis data structure patterns for production applications.

## When to Activate
- Implementing caching with Redis
- Building distributed locks or rate limiters
- Setting up pub/sub messaging
- Working with Redis data structures

## Caching Patterns

### Cache-Aside (Read)
```
GET /api/users/:id
  1. Check Redis cache → hit? return
  2. Query PostgreSQL
  3. Set Redis TTL (e.g., 300s)
  4. Return result
```

### Cache Invalidation
- **TTL-based**: auto-expire after N seconds
- **Write-through**: update cache on write
- **Event-driven**: pub/sub invalidation messages

## Data Structures

| Structure | Use Case | Example |
|-----------|----------|---------|
| String | Caching, counters | `SET user:123 "..."` |
| Hash | Objects | `HSET user:123 name "Alice"` |
| List | Queues, timeline | `LPUSH queue:emails ...` |
| Set | Unique items | `SADD tags:python "fastapi"` |
| Sorted Set | Leaderboards | `ZADD leaderboard 1000 "user1"` |

## Distributed Lock
```python
# SET with NX + EX
import redis.asyncio as aioredis

async def acquire_lock(redis, key, ttl=10):
    return await redis.set(f"lock:{key}", "1", nx=True, ex=ttl)
```

## Rate Limiting
```python
# Sliding window with Sorted Set
async def check_rate_limit(redis, key, max_requests=100, window=60):
    now = time.time()
    await redis.zremrangebyscore(f"ratelimit:{key}", 0, now - window)
    count = await redis.zcard(f"ratelimit:{key}")
    if count >= max_requests:
        return False
    await redis.zadd(f"ratelimit:{key}", {str(now): now})
    await redis.expire(f"ratelimit:{key}", window)
    return True
```

## Pitfalls
- ❌ Long TTLs on stale data
- ❌ No connection pooling in sync code
- ❌ Storing large objects in single keys
- ❌ Forgetting `expire` on locks
- ❌ Using Redis as primary database
