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
}
}
}
}
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
package api
import (
"net/http"
"runtime/debug"
)
Expose build metadata for debugging deploys
package dbutil
import (
"context"
"github.com/jackc/pgconn"
Retry Postgres serialization failures with bounded attempts
json.array! @posts do |post|
json.cache! ['v1', post], expires_in: 1.hour do
json.id post.id
json.title post.title
json.excerpt post.excerpt
json.published_at post.published_at
Fragment caching for expensive JSON serialization
import { randomBytes, createHash } from "crypto";
import jwt from "jsonwebtoken";
import { RefreshTokenStore } from "./store";
const ACCESS_SECRET = process.env.ACCESS_SECRET!;
const ACCESS_TTL = "15m";
JWT access + refresh token rotation (conceptual)
package files
import (
"context"
"time"
Presigned S3 upload URLs (AWS SDK v2)
package deps
import (
"net"
"net/http"
"time"
HTTP client tuned for production: timeouts, transport, and connection reuse
Share this code
Here's the card — post it anywhere.