Claude Cursor Skill

redis-connections

Redis client and connection guidance covering connection pooling, multiplexing, pipelining, client-side caching with RESP3, avoiding slow commands (KEYS, SMEMBERS, HGETALL), and tuning socket timeouts. Use when configuring a Redis client (redis-py, Jedis, Lettuce, NRedisStack), b

LLM Mart · 0 points · 8 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download redis-agent-skills-skills_redis-connections-172fb9e.zip · 6 KB
Part of redis/agent-skills — 12 skills

Install

skills CLI npx skills add https://github.com/redis/agent-skills/tree/main/skills/redis-connections
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install redis-agent-skills@llmmart
Git git clone https://github.com/redis/agent-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole redis/agent-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Redis Connections

Client-side guidance for talking to Redis efficiently: how to share connections, how to batch commands, which commands not to call in production, when to turn on client-side caching, and how to set timeouts that fail fast without breaking healthy traffic.

When to apply

  • Creating or reviewing a Redis client setup (redis-py, Jedis, Lettuce, go-redis, NRedisStack).
  • Making many small Redis calls and wondering where the latency is going.
  • Iterating large keyspaces, sets, hashes, or lists.
  • Enabling client-side caching for hot keys.
  • Tuning connect / read / write timeouts.

1. Pool or multiplex — never one connection per request

The single biggest mistake in Redis client code is opening a new TCP connection for every operation. Always either:

  • Pool — keep N persistent connections that the application leases per call (redis-py ConnectionPool, Jedis JedisPooled, go-redis client).
  • Multiplex — share a single connection across all requests (Lettuce, NRedisStack).
Style Used by Note
Pool redis-py, Jedis, go-redis Each lease blocks if pool exhausted; size the pool to your concurrency
Multiplex Lettuce, NRedisStack Single connection; cannot carry blocking commands like BLPOP
# redis-py — connection pool
pool = redis.ConnectionPool(host="localhost", port=6379, max_connections=50)
r = redis.Redis(connection_pool=pool)

See references/pooling.md for Python + Java + Lettuce examples.

2. Pipeline bulk work

For N commands that don't depend on each other's results, send them as a single batch with pipelining. One round-trip instead of N.

pipe = redis.pipeline()
for user_id in user_ids:
    pipe.get(f"user:{user_id}")
results = pipe.execute()

Use non-transactional pipelining for performance, and pipeline(transaction=True) only when you actually need atomicity (see redis-core's transactions guidance).

See references/pipelining.md.

3. Avoid commands that scan everything

Anything that walks the whole keyspace (or a whole large container) blocks the server. Use incremental variants instead.

Don't Use
KEYS pattern SCAN cursor loop
SMEMBERS large_set SSCAN
HGETALL large_hash HSCAN
LRANGE 0 -1 on a huge list Paginate (LRANGE 0 100)
cursor = 0
while True:
    cursor, keys = redis.scan(cursor, match="user:*", count=100)
    for key in keys:
        process(key)
    if cursor == 0:
        break

Blocking commands (BLPOP, BRPOP, BLMOVE) are different — they intentionally wait for data and are fine for queue consumers, but always pass a timeout, and don't issue them on a multiplexed connection (Lettuce, NRedisStack).

See references/blocking.md.

4. Client-side caching for hot keys

For data that's read often and written rarely (config, feature flags, sessions on every request), enable RESP3 client-side caching. The client keeps a local copy and the server invalidates it on writes — saving the round trip for hot reads.

client = redis.Redis(
    host="localhost",
    port=6379,
    protocol=3,                                    # RESP3 is required
    cache_config=redis.CacheConfig(max_size=1000),
)

Skip it for write-heavy workloads or data that changes constantly — the invalidation traffic overruns the savings.

See references/client-cache.md.

5. Set explicit timeouts

Defaults vary by client and may be too generous. Pick values that match the application's failure model:

r = redis.Redis(
    host="localhost",
    socket_connect_timeout=2.0,   # fail fast on dead nodes
    socket_timeout=5.0,           # tune to expected operation time
    retry_on_timeout=True,
)

Rule of thumb: connect timeout shorter than read/write timeout. Tight timeouts + retry-on-timeout for latency-sensitive paths; longer timeouts for batch jobs.

See references/timeouts.md.

References

Files (agent-skills)
  • references
    • blocking.md 1.8 KB
      # Avoid Slow Commands in Production
      
      Some Redis commands are slow because they scan large datasets. Use incremental alternatives to avoid blocking the server.
      
      | Avoid | Use Instead |
      |-------|-------------|
      | `KEYS *` | `SCAN` with cursor |
      | `SMEMBERS` on large sets | `SSCAN` |
      | `HGETALL` on large hashes | `HSCAN` |
      | `LRANGE 0 -1` on large lists | Paginate with `LRANGE 0 100` |
      
      **Correct:** Use SCAN for iteration.
      
      **Python** (redis-py):
      ```python
      # Good: Non-blocking iteration
      cursor = 0
      while True:
          cursor, keys = redis.scan(cursor, match="user:*", count=100)
          for key in keys:
              process(key)
          if cursor == 0:
              break
      ```
      
      **Java** (Jedis):
      ```java
      import redis.clients.jedis.ScanIteration;
      import redis.clients.jedis.UnifiedJedis;
      import java.util.List;
      
      try (UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379")) {
          // ScanIteration manages the cursor automatically
          ScanIteration scan = jedis.scanIteration(10, "user:*", "hash");
      
          while (!scan.isIterationCompleted()) {
              List<String> result = scan.nextBatch().getResult();
              for (String key : result) {
                  process(key);
              }
          }
      }
      ```
      
      **Incorrect:** Using KEYS in production.
      
      **Python** (redis-py):
      ```python
      # Bad: Scans all keys, slow on large datasets
      keys = redis.keys("user:*")
      ```
      
      **Java** (Jedis):
      ```java
      // Bad: Scans all keys, blocks the server
      Set<String> result = jedis.keys("*");
      ```
      
      **Note:** Truly blocking commands (like `BLPOP`, `BRPOP`, `BLMOVE`) that wait indefinitely for data are appropriate for some use cases like job queues, but should be used with timeouts.
      
      ```python
      # Blocking pop with timeout - appropriate for queue consumers
      result = redis.blpop("task_queue", timeout=5)
      ```
      
      Reference: [Redis SCAN](https://redis.io/docs/latest/commands/scan/)
      
    • client-cache.md 2 KB
      # Use Client-Side Caching for Frequently Read Data
      
      Use a connection with client-side caching enabled for any data that will be read frequently but written only occasionally. Client-side caching avoids contacting the server for repeated access to data that has recently been read, reducing network traffic and improving performance.
      
      **Correct:** Enable client-side caching with RESP3 protocol for frequently accessed data.
      
      **Python** (redis-py):
      ```python
      import redis
      
      # Enable client-side caching with RESP3
      client = redis.Redis(
          host='localhost',
          port=6379,
          protocol=3,  # RESP3 required for client-side caching
          cache_config=redis.CacheConfig(max_size=1000)
      )
      
      # Cached reads avoid server round-trips
      value = client.get("frequently:read:key")
      ```
      
      **Java** (Jedis):
      ```java
      import redis.clients.jedis.DefaultJedisClientConfig;
      import redis.clients.jedis.UnifiedJedis;
      import redis.clients.jedis.HostAndPort;
      import redis.clients.jedis.CacheConfig;
      
      HostAndPort endpoint = new HostAndPort("localhost", 6379);
      
      DefaultJedisClientConfig config = DefaultJedisClientConfig
          .builder()
          .password("secretPassword")
          .protocol(RedisProtocol.RESP3)
          .build();
      
      CacheConfig cacheConfig = CacheConfig.builder().maxSize(1000).build();
      
      UnifiedJedis client = new UnifiedJedis(endpoint, config, cacheConfig);
      ```
      
      **When to use:**
      - Configuration data read frequently, updated rarely
      - User session data accessed on every request
      - Feature flags or settings checked repeatedly
      - Any read-heavy workload with low write frequency
      
      **When NOT needed:**
      - Data that changes frequently (cache invalidation overhead outweighs benefits)
      - Write-heavy workloads
      - Simple applications where network latency is not a bottleneck
      - When you need guaranteed real-time consistency
      
      **Trade-offs:**
      - Adds memory overhead on the client
      - Requires RESP3 protocol
      - Cache invalidation adds complexity for frequently changing data
      
      Reference: [Client-side caching](https://redis.io/docs/latest/develop/clients/client-side-caching/)
      
    • pipelining.md 1.1 KB
      # Use Pipelining for Bulk Operations
      
      Batch multiple commands into a single round trip to reduce network latency.
      
      **Correct:** Use pipeline for multiple commands.
      
      **Python** (redis-py):
      ```python
      # Good: Single round trip for multiple commands
      pipe = redis.pipeline()
      for user_id in user_ids:
          pipe.get(f"user:{user_id}")
      results = pipe.execute()
      ```
      
      **Java** (Jedis):
      ```java
      import redis.clients.jedis.Pipeline;
      
      // Good: Buffer commands and send as single batch
      Pipeline pipe = (Pipeline) jedis.pipelined();
      
      pipe.set("person:1:name", "Alex");
      pipe.set("person:1:rank", "Captain");
      pipe.set("person:1:serial", "AB1234");
      
      pipe.sync();
      ```
      
      **Incorrect:** Sequential commands in a loop.
      
      **Python** (redis-py):
      ```python
      # Bad: N round trips
      results = []
      for user_id in user_ids:
          results.append(redis.get(f"user:{user_id}"))
      ```
      
      **Java** (Jedis):
      ```java
      // Bad: 3 separate round trips
      jedis.set("person:1:name", "Alex");
      jedis.set("person:1:rank", "Captain");
      jedis.set("person:1:serial", "AB1234");
      ```
      
      Reference: [Redis Pipelining](https://redis.io/docs/latest/develop/use/pipelining/)
      
    • pooling.md 1.9 KB
      # Use Connection Pooling or Multiplexing
      
      Reuse connections via a pool or multiplexing instead of creating new connections per request.
      
      **Correct:** Use a connection pool.
      
      **Python** (redis-py):
      ```python
      import redis
      
      # Good: Connection pool - reuses existing connections
      pool = redis.ConnectionPool(host='localhost', port=6379, max_connections=50)
      r = redis.Redis(connection_pool=pool)
      ```
      
      **Java** (Jedis):
      ```java
      import redis.clients.jedis.JedisPooled;
      
      // JedisPooled manages a connection pool internally
      try (JedisPooled jedis = new JedisPooled("redis://localhost:6379")) {
          jedis.set("testKey", "testValue");
      }
      ```
      
      **Correct:** Use multiplexing (Lettuce, NRedisStack).
      
      ```java
      // Lettuce uses multiplexing by default - single connection handles all traffic
      RedisClient client = RedisClient.create("redis://localhost:6379");
      StatefulRedisConnection<String, String> connection = client.connect();
      
      // All commands share the single connection efficiently
      connection.sync().set("key", "value");
      ```
      
      **Incorrect:** Creating new connections per request.
      
      **Python** (redis-py):
      ```python
      # Bad: New connection every time
      def get_user(user_id):
          r = redis.Redis(host='localhost', port=6379)  # Don't do this
          return r.get(f"user:{user_id}")
      ```
      
      **Java** (Jedis):
      ```java
      // Bad: Creating new client per request
      public String getUser(String userId) {
          try (UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379")) {
              return jedis.get("user:" + userId);  // Don't do this
          }
      }
      ```
      
      **Pooling vs Multiplexing:**
      - **Pooling**: Multiple connections shared across requests (redis-py, Jedis, go-redis)
      - **Multiplexing**: Single connection handles all traffic (NRedisStack, Lettuce)
      - Multiplexing cannot support blocking commands (BLPOP, etc.) as they would stall all callers
      
      Reference: [Connection Pools and Multiplexing](https://redis.io/docs/latest/develop/clients/pools-and-muxing/)
      
    • timeouts.md 1.3 KB
      # Configure Connection Timeouts
      
      Configure appropriate timeout values to improve your application's connection resilience. While most Redis clients set default timeouts, choosing well-tuned values based on your application's usage patterns leads to better failure recovery.
      
      **Correct:** Set timeouts based on your application needs.
      
      ```python
      r = redis.Redis(
          host='localhost',
          socket_timeout=5.0,          # Read/write timeout - tune based on expected operation time
          socket_connect_timeout=2.0,  # Connection timeout - shorter for fast failure detection
          retry_on_timeout=True        # Automatic retry on timeout
      )
      ```
      
      **Incorrect:** Relying solely on defaults without considering your use case.
      
      ```python
      # Not ideal: Default timeouts may not match your application's needs
      r = redis.Redis(host='localhost')
      
      # For example, if your app needs fast failure detection,
      # the default timeouts might be too generous
      ```
      
      **Considerations:**
      - Set `socket_connect_timeout` shorter than `socket_timeout` for quick connection failure detection
      - For latency-sensitive apps, use tighter timeouts with retry logic
      - For batch operations, allow longer timeouts to complete large operations
      - Consider using health checks alongside timeouts for robust failure handling
      
      Reference: [Redis Client Configuration](https://redis.io/docs/latest/develop/clients/)
      
  • SKILL.md 5 KB
    ---
    name: redis-connections
    description: Redis client and connection guidance covering connection pooling, multiplexing, pipelining, client-side caching with RESP3, avoiding slow commands (KEYS, SMEMBERS, HGETALL), and tuning socket timeouts. Use when configuring a Redis client (redis-py, Jedis, Lettuce, NRedisStack), batching commands for throughput, eliminating per-request connection creation, iterating large keyspaces with SCAN, enabling client-side caching for read-heavy workloads, or setting connect and read timeouts.
    license: MIT
    metadata:
      author: Redis, Inc.
      version: "0.1.0"
    ---
    
    # Redis Connections
    
    Client-side guidance for talking to Redis efficiently: how to share connections, how to batch commands, which commands not to call in production, when to turn on client-side caching, and how to set timeouts that fail fast without breaking healthy traffic.
    
    ## When to apply
    
    - Creating or reviewing a Redis client setup (redis-py, Jedis, Lettuce, go-redis, NRedisStack).
    - Making many small Redis calls and wondering where the latency is going.
    - Iterating large keyspaces, sets, hashes, or lists.
    - Enabling client-side caching for hot keys.
    - Tuning connect / read / write timeouts.
    
    ## 1. Pool or multiplex — never one connection per request
    
    The single biggest mistake in Redis client code is opening a new TCP connection for every operation. Always either:
    
    - **Pool** — keep N persistent connections that the application leases per call (redis-py `ConnectionPool`, Jedis `JedisPooled`, go-redis client).
    - **Multiplex** — share a single connection across all requests (Lettuce, NRedisStack).
    
    | Style | Used by | Note |
    |---|---|---|
    | Pool | redis-py, Jedis, go-redis | Each lease blocks if pool exhausted; size the pool to your concurrency |
    | Multiplex | Lettuce, NRedisStack | Single connection; **cannot** carry blocking commands like `BLPOP` |
    
    ```python
    # redis-py — connection pool
    pool = redis.ConnectionPool(host="localhost", port=6379, max_connections=50)
    r = redis.Redis(connection_pool=pool)
    ```
    
    See [references/pooling.md](references/pooling.md) for Python + Java + Lettuce examples.
    
    ## 2. Pipeline bulk work
    
    For N commands that don't depend on each other's results, send them as a single batch with pipelining. One round-trip instead of N.
    
    ```python
    pipe = redis.pipeline()
    for user_id in user_ids:
        pipe.get(f"user:{user_id}")
    results = pipe.execute()
    ```
    
    Use **non-transactional** pipelining for performance, and `pipeline(transaction=True)` only when you actually need atomicity (see redis-core's transactions guidance).
    
    See [references/pipelining.md](references/pipelining.md).
    
    ## 3. Avoid commands that scan everything
    
    Anything that walks the whole keyspace (or a whole large container) blocks the server. Use incremental variants instead.
    
    | Don't | Use |
    |---|---|
    | `KEYS pattern` | `SCAN` cursor loop |
    | `SMEMBERS large_set` | `SSCAN` |
    | `HGETALL large_hash` | `HSCAN` |
    | `LRANGE 0 -1` on a huge list | Paginate (`LRANGE 0 100`) |
    
    ```python
    cursor = 0
    while True:
        cursor, keys = redis.scan(cursor, match="user:*", count=100)
        for key in keys:
            process(key)
        if cursor == 0:
            break
    ```
    
    **Blocking commands (`BLPOP`, `BRPOP`, `BLMOVE`) are different** — they intentionally wait for data and are fine for queue consumers, but always pass a timeout, and don't issue them on a multiplexed connection (Lettuce, NRedisStack).
    
    See [references/blocking.md](references/blocking.md).
    
    ## 4. Client-side caching for hot keys
    
    For data that's read often and written rarely (config, feature flags, sessions on every request), enable RESP3 client-side caching. The client keeps a local copy and the server invalidates it on writes — saving the round trip for hot reads.
    
    ```python
    client = redis.Redis(
        host="localhost",
        port=6379,
        protocol=3,                                    # RESP3 is required
        cache_config=redis.CacheConfig(max_size=1000),
    )
    ```
    
    Skip it for write-heavy workloads or data that changes constantly — the invalidation traffic overruns the savings.
    
    See [references/client-cache.md](references/client-cache.md).
    
    ## 5. Set explicit timeouts
    
    Defaults vary by client and may be too generous. Pick values that match the *application's* failure model:
    
    ```python
    r = redis.Redis(
        host="localhost",
        socket_connect_timeout=2.0,   # fail fast on dead nodes
        socket_timeout=5.0,           # tune to expected operation time
        retry_on_timeout=True,
    )
    ```
    
    Rule of thumb: connect timeout shorter than read/write timeout. Tight timeouts + retry-on-timeout for latency-sensitive paths; longer timeouts for batch jobs.
    
    See [references/timeouts.md](references/timeouts.md).
    
    ## References
    
    - [Redis: Connection Pools and Multiplexing](https://redis.io/docs/latest/develop/clients/pools-and-muxing/)
    - [Redis: Pipelining](https://redis.io/docs/latest/develop/use/pipelining/)
    - [Redis: SCAN](https://redis.io/docs/latest/commands/scan/)
    - [Redis: Client-side caching](https://redis.io/docs/latest/develop/clients/client-side-caching/)
    - [Redis: Clients](https://redis.io/docs/latest/develop/clients/)
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related