Source profileQuality 84/100

affaan-m/ECC/docs/ja-JP/skills/redis-patterns/SKILL.md

redis-patterns

Use it for design tasks; the detail page covers purpose, installation, and practical steps.

Source repository stars
234,327
Declared platforms
0
Static risk flags
0
Last source update
2026-07-27
Source checked
2026-07-28

Decision brief

What it does—and where it fits

一般的なバックエンド使用例に対するRedisベストプラクティスの参考資料。

Best for

    Not for

    • マルチプロセスデプロイメント:インプロセスロックを上記の分散ロックセクション から acquirelock/releaselock に置き換えてください。
    • Cache Miss Stampede Prevention

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/affaan-m/ECC --skill "docs/ja-JP/skills/redis-patterns"
    Safe inspection promptEditorial

    Inspect the Agent Skill "redis-patterns" from https://github.com/affaan-m/ECC/blob/4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38/docs/ja-JP/skills/redis-patterns/SKILL.md at commit 4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Usage

      token = acquirelock("order:payment:123") if token: try: processpayment() finally: releaselock("order:payment:123", token) python

      token = acquirelock("order:payment:123") if token: try: processpayment() finally: releaselock("order:payment:123", token) python
    2. 02

      Subscriber (blocking — run in separate thread/process)

      def subscribeevents(channel: str): pubsub = r.pubsub() pubsub.subscribe(channel) for message in pubsub.listen(): if message['type'] == 'message': handle(json.loads(message['data'])) python

      def subscribeevents(channel: str): pubsub = r.pubsub() pubsub.subscribe(channel) for message in pubsub.listen(): if message['type'] == 'message': handle(json.loads(message['data'])) python
    3. 03

      How It Works

      Redisはメモリ内データ構造ストアで、文字列、ハッシュ、リスト、セット、ソート済みセット、ストリームなどをサポートします。単一インスタンスでは個々のRedisコマンドは原子的ですが、マルチステップワークフローはLuaスクリプト、MULTI/EXECトランザクション、または明示的な同期化が必要です。RDBスナップショットまたはAOFログを通じてデータをオプションで永続化します。クライアントはRESPプロトコルを使用してTCP経由で通信します。接続プール不可欠でリクエストごとのハンドシェイクオーバーヘッドを回避します。

      Redisはメモリ内データ構造ストアで、文字列、ハッシュ、リスト、セット、ソート済みセット、ストリームなどをサポートします。単一インスタンスでは個々のRedisコマンドは原子的ですが、マルチステップワークフローはLuaスクリプト、MULTI/EXECトランザクション、または明示的な同期化が必要です。RDBスナップショットまたはAOFログを通じてデータをオプションで永続化します。クライアントはRESPプロトコルを使用してTCP経由で通信…
    4. 04

      When to Activate

      アプリケーションにキャッシング追加

      アプリケーションにキャッシング追加レート制限またはスロットリング実装分散ロックまたはコーディネーション構築
    5. 05

      Data Structure Cheat Sheet

      Review the “Data Structure Cheat Sheet” section in the pinned source before continuing.

      Review and apply the “Data Structure Cheat Sheet” source section.

    Permission review

    Static risk signals and limitations

    No configured static risk pattern was detected

    This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score84/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars234,327SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    affaan-m/ECC
    Skill path
    docs/ja-JP/skills/redis-patterns/SKILL.md
    Commit
    4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38
    License
    MIT
    Collected
    2026-07-28
    Default branch
    main
    View the original SKILL.md

    Redis Patterns

    一般的なバックエンド使用例に対するRedisベストプラクティスの参考資料。

    How It Works

    Redisはメモリ内データ構造ストアで、文字列、ハッシュ、リスト、セット、ソート済みセット、ストリームなどをサポートします。単一インスタンスでは個々のRedisコマンドは原子的ですが、マルチステップワークフローはLuaスクリプト、MULTI/EXECトランザクション、または明示的な同期化が必要です。RDBスナップショットまたはAOFログを通じてデータをオプションで永続化します。クライアントはRESPプロトコルを使用してTCP経由で通信します。接続プール不可欠でリクエストごとのハンドシェイクオーバーヘッドを回避します。

    When to Activate

    • アプリケーションにキャッシング追加
    • レート制限またはスロットリング実装
    • 分散ロックまたはコーディネーション構築
    • セッションまたはトークンストレージ設定
    • Pub/SubまたはRedis Streams for messaging使用
    • 本番環境でRedis設定(プール、削除、クラスタリング)

    Data Structure Cheat Sheet

    Use CaseStructureExample Key
    Simple cacheStringproduct:123
    User sessionHashsession:abc
    LeaderboardSorted Setscores:weekly
    Unique visitorsSetvisitors:2024-01-01
    Activity feedListfeed:user:456
    Event streamStreamevents:orders
    Counters / rate limitsString (INCR)ratelimit:user:123
    Bloom filter / HLLHyperLogLoghll:pageviews

    Core Patterns

    Cache-Aside (Lazy Loading)

    import redis
    import json
    
    r = redis.Redis(host='localhost', port=6379, decode_responses=True)
    
    def get_product(product_id: int):
        cache_key = f"product:{product_id}"
        cached = r.get(cache_key)
    
        if cached:
            return json.loads(cached)
    
        product = db.query("SELECT * FROM products WHERE id = %s", product_id)
        r.setex(cache_key, 3600, json.dumps(product))  # TTL: 1 hour
        return product
    

    Write-Through Cache

    def update_product(product_id: int, data: dict):
        # DB書き込み先
        db.execute("UPDATE products SET ... WHERE id = %s", product_id)
    
        # キャッシュを即座に更新
        cache_key = f"product:{product_id}"
        r.setex(cache_key, 3600, json.dumps(data))
    

    Cache Invalidation

    # タグベース削除 — セット内で関連キーをグループ化
    def cache_product(product_id: int, category_id: int, data: dict):
        key = f"product:{product_id}"
        tag = f"tag:category:{category_id}"
        pipe = r.pipeline(transaction=True)
        pipe.setex(key, 3600, json.dumps(data))
        pipe.sadd(tag, key)
        pipe.expire(tag, 3600)
        pipe.execute()
    
    def invalidate_category(category_id: int):
        tag = f"tag:category:{category_id}"
        keys = r.smembers(tag)
        if keys:
            r.delete(*keys)
        r.delete(tag)
    

    Session Storage

    import time
    import uuid
    
    def create_session(user_id: int, ttl: int = 86400) -> str:
        session_id = str(uuid.uuid4())
        key = f"session:{session_id}"
        pipe = r.pipeline(transaction=True)
        pipe.hset(key, mapping={
            "user_id": user_id,
            "created_at": int(time.time()),
        })
        pipe.expire(key, ttl)
        pipe.execute()
        return session_id
    
    def get_session(session_id: str) -> dict | None:
        data = r.hgetall(f"session:{session_id}")
        return data if data else None
    
    def delete_session(session_id: str):
        r.delete(f"session:{session_id}")
    

    Rate Limiting

    Fixed Window (Simple)

    def is_rate_limited(user_id: int, limit: int = 100, window: int = 60) -> bool:
        key = f"ratelimit:{user_id}:{int(time.time()) // window}"
        pipe = r.pipeline(transaction=True)
        pipe.incr(key)
        pipe.expire(key, window)
        count, _ = pipe.execute()
        return count > limit
    

    Sliding Window (Lua — Atomic)

    -- sliding_window.lua
    local key = KEYS[1]
    local now = tonumber(ARGV[1])
    local window = tonumber(ARGV[2])
    local limit = tonumber(ARGV[3])
    
    redis.call('ZREMRANGEBYSCORE', key, 0, now - window)
    local count = redis.call('ZCARD', key)
    
    if count < limit then
        -- Use unique member (now + sequence) to avoid collisions within the same millisecond
        local seq_key = key .. ':seq'
        local seq = redis.call('INCR', seq_key)
        redis.call('EXPIRE', seq_key, math.ceil(window / 1000))
        redis.call('ZADD', key, now, now .. '-' .. seq)
        redis.call('EXPIRE', key, math.ceil(window / 1000))
        return 1
    end
    return 0
    
    sliding_window = r.register_script(open('sliding_window.lua').read())
    
    def allow_request(user_id: int) -> bool:
        key = f"ratelimit:sliding:{user_id}"
        now = int(time.time() * 1000)
        return bool(sliding_window(keys=[key], args=[now, 60000, 100]))
    

    Distributed Locks

    Distributed Lock (Single Node — SET NX PX)

    import uuid
    
    def acquire_lock(resource: str, ttl_ms: int = 5000) -> str | None:
        lock_key = f"lock:{resource}"
        token = str(uuid.uuid4())
        acquired = r.set(lock_key, token, px=ttl_ms, nx=True)
        return token if acquired else None
    
    def release_lock(resource: str, token: str) -> bool:
        release_script = """
        if redis.call('get', KEYS[1]) == ARGV[1] then
            return redis.call('del', KEYS[1])
        else
            return 0
        end
        """
        result = r.eval(release_script, 1, f"lock:{resource}", token)
        return bool(result)
    
    # Usage
    token = acquire_lock("order:payment:123")
    if token:
        try:
            process_payment()
        finally:
            release_lock("order:payment:123", token)
    

    マルチノード設定の場合、フルRedlockアルゴリズムを実装する redlock-py ライブラリを使用してください。

    Pub/Sub & Streams

    Pub/Sub (Fire-and-Forget)

    # Publisher
    def publish_event(channel: str, payload: dict):
        r.publish(channel, json.dumps(payload))
    
    # Subscriber (blocking — run in separate thread/process)
    def subscribe_events(channel: str):
        pubsub = r.pubsub()
        pubsub.subscribe(channel)
        for message in pubsub.listen():
            if message['type'] == 'message':
                handle(json.loads(message['data']))
    

    Redis Streams (Durable Queue)

    # Producer
    def emit(stream: str, event: dict):
        r.xadd(stream, event, maxlen=10000)  # Cap stream length
    
    # Consumer group — guarantees at-least-once delivery
    try:
        r.xgroup_create('events:orders', 'processor', id='0', mkstream=True)
    except Exception:
        pass  # Group already exists
    
    def consume(stream: str, group: str, consumer: str):
        while True:
            messages = r.xreadgroup(group, consumer, {stream: '>'}, count=10, block=2000)
            for _, entries in (messages or []):
                for msg_id, data in entries:
                    process(data)
                    r.xack(stream, group, msg_id)
    

    配信保証、コンシューマーグループ、または再生が必要な場合、Pub/Sub代わりにStreamsを優先してください。

    Key Design

    Naming Conventions

    # Pattern: resource:id:field
    user:123:profile
    order:456:status
    cache:product:789
    
    # Pattern: namespace:resource:id
    myapp:session:abc123
    myapp:ratelimit:user:123
    
    # Pattern: resource:date (time-bound keys)
    stats:pageviews:2024-01-01
    

    TTL Strategy

    Data TypeSuggested TTL
    User session24h (86400)
    API response cache5–15 min
    Rate limit windowMatch window size
    Short-lived tokens5–10 min
    Leaderboard1h–24h
    Static/reference data1h–1 week

    常にTTLを設定してください。TTLなしのキーは無限に蓄積してメモリ圧力を引き起こします。

    Connection Management

    Connection Pooling

    from redis import ConnectionPool, Redis
    
    pool = ConnectionPool(
        host='localhost',
        port=6379,
        db=0,
        max_connections=20,
        decode_responses=True,
        socket_connect_timeout=2,
        socket_timeout=2,
    )
    
    r = Redis(connection_pool=pool)
    

    Cluster Mode

    from redis.cluster import RedisCluster
    
    r = RedisCluster(
        startup_nodes=[{"host": "redis-1", "port": 6379}],
        decode_responses=True,
        skip_full_coverage_check=True,
    )
    

    Sentinel (High Availability)

    from redis.sentinel import Sentinel
    
    sentinel = Sentinel(
        [('sentinel-1', 26379), ('sentinel-2', 26379)],
        socket_timeout=0.5,
    )
    master = sentinel.master_for('mymaster', decode_responses=True)
    replica = sentinel.slave_for('mymaster', decode_responses=True)
    

    Eviction Policies

    PolicyBehaviorBest For
    noevictionError on write when fullQueues / critical data
    allkeys-lruEvict least recently usedGeneral cache
    volatile-lruLRU only among keys with TTLMixed data store
    allkeys-lfuEvict least frequently usedSkewed access patterns
    volatile-ttlEvict soonest-to-expirePrioritize long-lived data

    redis.confを通じて設定:maxmemory-policy allkeys-lru

    Anti-Patterns

    Anti-PatternProblemFix
    Keys with no TTLMemory grows unboundedAlways set TTL
    KEYS * in productionBlocks the server (O(N))Use SCAN cursor
    Storing large blobs (>100KB)Slow serialization, memory pressureStore reference + fetch from object store
    Single Redis for everythingNo isolation between cache & queueUse separate DBs or instances
    Ignoring connection pool limitsConnection exhaustion under loadSize pool to workload
    Not handling cache miss stampedeThundering herd on cold startUse locks or probabilistic early expiry
    FLUSHALL without thoughtWipes entire instanceScope deletes by key pattern

    Cache Miss Stampede Prevention

    import threading
    
    _locks: dict[str, threading.Lock] = {}
    _locks_mutex = threading.Lock()
    
    def get_with_lock(key: str, fetch_fn, ttl: int = 300):
        cached = r.get(key)
        if cached:
            return json.loads(cached)
    
        with _locks_mutex:
            if key not in _locks:
                _locks[key] = threading.Lock()
            lock = _locks[key]
        with lock:
            cached = r.get(key)  # Re-check after acquiring lock
            if cached:
                return json.loads(cached)
            value = fetch_fn()
            r.setex(key, ttl, json.dumps(value))
            return value
    

    マルチプロセスデプロイメント:インプロセスロックを上記の分散ロックセクション から acquire_lock/release_lock に置き換えてください。

    Examples

    Django/Flask APIエンドポイントにキャッシング追加: レスポンスに5分TTLでCache-asideを使用。リクエストパラメータでキーを指定。

    ユーザーごとにAPIレート制限: 低トラフィックエンドポイントに固定ウィンドウを pipeline(transaction=True) で使用;正確なユーザーごと制限にはsliding-windowの Lua使用。

    ワーカー間のバックグラウンドジョブ調整: 予想ジョブ期間を超えるTTLで acquire_lock を使用。常に finally ブロックでリリース。

    複数購読者への通知のファンアウト: ファイアアンドフォーゲットにPub/Subを使用。保証配信または再生が必要な場合、Streamsに切り替え。

    Quick Reference

    PatternWhen to Use
    Cache-asideRead-heavy, tolerate slight staleness
    Write-throughStrong consistency required
    Distributed lockPrevent concurrent access to a resource
    Sliding window rate limitAccurate per-user throttling
    Redis StreamsDurable event queue with consumer groups
    Pub/SubBroadcast with no delivery guarantees needed
    Sorted Set leaderboardRanked scoring, pagination
    HyperLogLogApproximate unique count at low memory

    Related

    • Skill: postgres-patterns — リレーショナルデータパターン
    • Skill: backend-patterns — APIおよびサービスレイヤーパターン
    • Skill: database-migrations — スキーマバージョニング
    • Skill: django-patterns — Djangoキャッシュフレームワーク統合
    • Agent: database-reviewer — 全データベースレビューワークフロー

    Alternatives

    Compare before choosing

    Computed 90234,327

    affaan-m/ECC

    redis-patterns

    Redis data structure patterns, caching strategies, distributed locks, rate limiting, pub/sub, and connection management for production applications.

    Computed 10042,015

    coreyhaines31/marketingskills

    ab-testing

    When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program

    Computed 10042,015

    coreyhaines31/marketingskills

    churn-prevention

    When the user wants to reduce churn, build cancellation flows, set up save offers, recover failed payments, or implement retention strategies. Also use when the user mentions 'churn,' 'cancel flow,' 'offboarding,' 'save offer,' 'dunning,' 'failed payment recovery,' 'win-back,' 'retention,' 'exit survey,' 'pause subscription,' 'involuntary churn,' 'people keep canceling,' 'churn rate is too high,' 'how do I keep users,' or 'customers are leaving.' Use this whenever someone is losing subscribers o

    Computed 1007

    event4u-app/agent-config

    design-intelligence

    Grounded design brief from the adopted corpus — style, WCAG-checked color tokens, typography, layout pattern, anti-patterns. Use on ui-design-brief or any which-style/palette/font/chart decision.