L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Productivité · SKILL.md

redis-sdk

redis-sdk

Integrates Redis using redis-py 5.x with patterns for caching, streams, pub/sub, sorted sets, Redis Stack modules (JSON, Search, TimeSeries), and cluster connections.

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: redis-sdk description: Integrates Redis using redis-py 5.x with patterns for caching, streams, pub/sub, sorted sets, Redis Stack modules (JSON, Search, TimeSeries), and cluster connections. license: MIT compatibility: opencode metadata: version: "1.0.0" domain: coding triggers: redis, redis-py, redis cache, redis streams, redis pub/sub, how do i use redis from python, redis stack, redis cluster archetypes:

  • tactical
  • generation anti_triggers:
  • brainstorming
  • vague ideation
  • code golf
  • over-engineering response_profile: verbosity: low directive_strength: high abstraction_level: operational role: implementation scope: implementation output-format: code content-types:
  • code
  • guidance
  • do-dont
  • examples related-skills: coding-postgresql-sdk, coding-mongodb-driver, coding-caching-strategies

Redis Python SDK (redis-py) Integration

Integrates Redis using redis-py 5.x — the official Python Redis client — with patterns for caching, streams, pub/sub, sorted sets (leaderboards), Redis Stack modules (JSON, Search, TimeSeries), pipeline transactions, and cluster/sentinel connections.

TL;DR Checklist

  • Use redis.Redis() for standalone, redis.cluster.RedisCluster for cluster mode
  • Use pipeline() for atomic multi-command transactions
  • Use XADD / XREAD for stream-based message queues (not Pub/Sub for durable messaging)
  • Use SETEX or PSETEX for time-bound caching
  • Use ZADD / ZRANK / ZRANGEBYSCORE for leaderboards and range queries
  • Use redis-py Stack modules (JSON, Search) when using Redis Stack
  • Use Redis Sentinel for high-availability connections

When to Use

Use this skill when:

  • Implementing distributed caching with TTL-based expiration
  • Building real-time message queues with Redis Streams (consumer groups, acknowledgments)
  • Implementing pub/sub for real-time notifications (WebSocket backends, event broadcasting)
  • Building leaderboards or time-series data with sorted sets
  • Managing rate limits with atomic counters (INCR + EXPIRE)
  • Using Redis Stack for document storage (JSON), search (RediSearch), or time-series (RedisTimeSeries)
  • Connecting to Redis Cluster or Redis Sentinel deployments from Python

When NOT to Use

  • For persistent relational data with complex queries (use PostgreSQL)
  • For document storage at scale (use MongoDB instead)
  • For message queues requiring persistence guarantees (use RabbitMQ or Kafka instead)
  • For data larger than available RAM (Redis is an in-memory store)
  • For complex aggregation queries (use Elasticsearch or MongoDB instead)

Core Workflow

1. Connect to Redis

import redis
from redis.exceptions import RedisError, ConnectionError, TimeoutError

# Standalone Redis
r = redis.Redis(
    host="localhost",
    port=6379,
    db=0,
    decode_responses=True,     # Return strings instead of bytes
    socket_connect_timeout=5,
    socket_timeout=10,
    retry_on_timeout=True,
    health_check_interval=30,
)

# Redis Sentinel (high availability)
from redis.sentinel import Sentinel

sentinel = Sentinel(
    [("sentinel1", 26379), ("sentinel2", 26379)],
    socket_timeout=0.5,
)
r = sentinel.master_for("mymaster", db=0, decode_responses=True)

Checkpoint: Verify connectivity with r.ping(). Catch ConnectionError at startup — do not let operations fail silently on a dead connection.

2. Basic Key-Value Operations with TTL

from typing import Any, Optional

def cache_set(
    r: redis.Redis,
    key: str,
    value: Any,
    ttl_seconds: int = 300,
) -> None:
    """Set a cache value with TTL. Serializes non-string values as JSON."""
    import json
    if not isinstance(value, (str, bytes)):
        value = json.dumps(value)
    r.setex(key, ttl_seconds, value)

def cache_get(r: redis.Redis, key: str) -> Optional[Any]:
    """Get a cache value, deserializing JSON if applicable."""
    value = r.get(key)
    if value is None:
        return None
    try:
        import json
        return json.loads(value)
    except (json.JSONDecodeError, TypeError):
        return value

Checkpoint: Always set TTL for cache keys to prevent memory exhaustion. Use EXISTS to check key presence without fetching value.

3. Pipeline Transactions

Use pipelines for atomic multi-key operations and reducing round-trips.

def transfer_leaderboard_points(
    r: redis.Redis,
    from_player: str,
    to_player: str,
    points: int,
) -> bool:
    """Atomically transfer points between two players in a leaderboard."""
    pipe = r.pipeline(transaction=True)
    try:
        pipe.zincrby("leaderboard", -points, from_player)
        pipe.zincrby("leaderboard", points, to_player)
        pipe.execute()
        return True
    except RedisError:
        return False

Checkpoint: Use pipeline(transaction=True) for atomicity when multiple keys must change together. Always handle RedisError on execute().

4. Redis Streams for Reliable Message Queues

import time

def produce_message(r: redis.Redis, stream: str, data: dict) -> str:
    """Add a message to a stream and return its ID."""
    return r.xadd(stream, data, maxlen=10000)  # Capped stream

def consume_messages(
    r: redis.Redis,
    stream: str,
    group: str,
    consumer: str,
    count: int = 10,
    block_ms: int = 5000,
) -> list[dict]:
    """Read and acknowledge messages from a consumer group."""
    # Create group if it doesn't exist (idempotent)
    try:
        r.xgroup_create(stream, group, id="0", mkstream=True)
    except redis.exceptions.ResponseError as exc:
        if "BUSYGROUP" not in str(exc):
            raise

    # Read pending and new messages
    results = r.xreadgroup(group, consumer, {stream: ">"}, count=count, block=block_ms)
    messages = []
    for stream_name, entries in results:
        for msg_id, msg_data in entries:
            messages.append({"id": msg_id, "data": msg_data})
            r.xack(stream, group, msg_id)  # Acknowledge after processing
    return messages

Checkpoint: Always acknowledge messages with XACK after successful processing to prevent redelivery. Use consumer groups for load-balanced stream consumption.


Implementation Patterns

Pattern 1: Rate Limiter with INCR + EXPIRE

def check_rate_limit(
    r: redis.Redis,
    key: str,
    max_requests: int,
    window_seconds: int,
) -> bool:
    """Check if a rate limit has been exceeded. Returns True if allowed."""
    current = r.incr(key)
    if current == 1:
        r.expire(key, window_seconds)
    return current <= max_requests

Pattern 2: Redis Stack JSON Documents

from redis.commands.json.path import Path

def set_json_doc(r: redis.Redis, key: str, doc: dict) -> None:
    """Store a JSON document using Redis JSON module."""
    r.json().set(key, Path.root_path(), doc)

def get_json_field(r: redis.Redis, key: str, field_path: str = "quot;) -> list:
    """Query a JSON document field path."""
    return r.json().get(key, field_path)

Pattern 3: Pub/Sub with Pattern Matching

def publish_event(r: redis.Redis, channel: str, event: dict) -> int:
    """Publish an event to a channel. Returns subscriber count."""
    import json
    return r.publish(channel, json.dumps(event))

def listen_for_events(r: redis.Redis, pattern: str):
    """Subscribe to events matching a glob pattern."""
    pubsub = r.pubsub()
    pubsub.psubscribe(pattern)
    for message in pubsub.listen():
        if message["type"] == "pmessage":
            yield message["data"]

BAD vs GOOD: Caching Pattern

# ❌ BAD — No TTL, no serialization handling, no connection check
def get_user_bad(r, user_id: str):
    data = r.get(f"user:{user_id}")
    return data

# ✅ GOOD — TTL-based caching with proper serialization
def get_user_good(r: redis.Redis, user_id: str) -> Optional[dict]:
    """Get cached user, returning None on cache miss."""
    import json
    try:
        data = r.get(f"user:{user_id}")
        if data is None:
            return None
        return json.loads(data)
    except (RedisError, json.JSONDecodeError):
        return None

BAD vs GOOD: Stream Consumption

# ❌ BAD — No consumer group, no acknowledgment, no error handling
def consume_bad(r, stream):
    while True:
        results = r.xread({stream: "quot;}, block=1000)
        for _, entries in results:
            for msg_id, data in entries:
                process(data)  # If this fails, message is lost

# ✅ GOOD — Consumer group with XACK
def consume_good(r: redis.Redis, stream: str, group: str, consumer: str):
    """Reliable stream consumer with acknowledgment."""
    for message in consume_messages(r, stream, group, consumer):
        try:
            process(message["data"])
        except Exception:
            # Move to dead-letter stream on processing failure
            r.xadd(f"{stream}:dlq", message["data"])
            r.xack(stream, group, message["id"])

Constraints

MUST DO

  • Always call r.close() in shutdown hooks or use connection pool context managers
  • Set decode_responses=True for string-based workflows (eliminates manual .decode() calls)
  • Use SETEX or PSETEX for all cache entries — Redis is memory-bound, TTL prevents exhaustion
  • Use pipeline transactions for atomic multi-key operations
  • Use health_check_interval in production to detect dead connections
  • Use consumer groups for reliable stream processing with acknowledgment

MUST NOT DO

  • Never use KEYS * in production — use SCAN for iterating keys
  • Do not store large values (>10MB) in Redis — it blocks the event loop
  • Do not use Pub/Sub for message delivery guarantees — subscribers miss messages on disconnect
  • Avoid single-key rate limits without TTL — keys accumulate forever
  • Never hardcode Redis connection parameters — use environment variables or config

Output Template

When writing Redis integration code, structure your output as:

  1. Connection Setup — Redis client with host, port, db, decode_responses, timeouts
  2. Data Structure Selection — String (cache), List (queue), Set (tags), Sorted Set (leaderboard), Stream (message queue)
  3. Operation — Command with proper arguments and error handling
  4. TTL Management — EXPIRE or SETEX for cache entries
  5. Cleanup — Close connection in finally / context manager

Related Skills

SkillPurpose
coding-postgresql-sdkPostgreSQL for persistent relational storage alongside Redis cache
coding-caching-strategiesCache-aside, write-through, and invalidation patterns
coding-asyncio-patternsAsync Redis with redis-py asyncio support

Live References

Skills enregistrées