go 27 lines · 1 tab

Redis Pub/Sub subscriber with reconnect-friendly loop

Leah Thompson Jan 2026
1 tab
package cache

import (
  "context"

  "github.com/redis/go-redis/v9"
)

func Subscribe(ctx context.Context, rdb *redis.Client, channel string, fn func(string) error) error {
  sub := rdb.Subscribe(ctx, channel)
  defer sub.Close()

  ch := sub.Channel()
  for {
    select {
    case <-ctx.Done():
      return ctx.Err()
    case msg, ok := <-ch:
      if !ok {
        return nil
      }
      if err := fn(msg.Payload); err != nil {
        return err
      }
    }
  }
}
1 file · go Explain with highlit

Pub/Sub consumers should assume connections will drop: Redis restarts, network blips, or idle timeouts happen. I keep the subscription loop simple: subscribe, range over the channel, and exit cleanly when ctx.Done() fires. If the subscription ends unexpectedly, the caller can restart the loop with backoff. The key is not leaking goroutines: always Close() the subscription and stop processing when the context is canceled. In production, I also add a “dead letter” path for messages that fail processing and I expose metrics for message lag (or at least throughput). Pub/Sub is not a durable queue, so I only use it for ephemeral notifications and cache invalidation, not for “must not lose” jobs. But when used appropriately, it’s a lightweight and very effective tool.


Related snips

Share this code

Here's the card — post it anywhere.

Redis Pub/Sub subscriber with reconnect-friendly loop — share card
Link copied