redis

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 23, 2026 License: MIT Imports: 7 Imported by: 0

README

go-redis 🧰

Resilient Redis wiring for Go in one call — sensible pool, timeouts, and retries by default, with sentinel failover, cluster, and a health check built in.

go-redis wraps redis/go-redis/v9 so a service stops re-deriving the same pool sizes, timeouts, and retry policy in every codebase. Connect returns a client that has already Pinged the server, so a successful call means you are ready to serve.

📦 Install

go get github.com/Bugs5382/go-redis

🚀 Usage

Connect applies resilient defaults, dials, and verifies readiness with a Ping. Redis() hands you the full go-redis command API.

client, err := redis.Connect(ctx, redis.WithAddr("localhost:6379"))
if err != nil {
	log.Fatal(err)
}
defer client.Close()

rdb := client.Redis()
rdb.Set(ctx, "session:123", "alice", time.Minute)
name, _ := rdb.Get(ctx, "session:123").Result()

🧩 Depend on go-redis only

Nil, Cmdable, and UniversalClient re-export the handful of go-redis names a caller needs in order to name the value Redis() returns, so a wrapper library can depend on go-redis alone and never import github.com/redis/go-redis/v9 directly:

var cmd redis.Cmdable = client.Redis() // or redis.UniversalClient

_, err := cmd.Get(ctx, "session:missing").Result()
if errors.Is(err, redis.Nil) {
	// cache miss
}

🛟 High availability

Point at Redis Sentinel for automatic failover — the client discovers the current master through the sentinels and re-resolves it after a switchover. Redis Cluster is one option away.

// Sentinel-managed failover master.
client, _ := redis.Connect(ctx,
	redis.WithSentinel("mymaster", "localhost:26379", "localhost:26380"),
)

// Redis Cluster.
client, _ := redis.Connect(ctx,
	redis.WithCluster("localhost:7000", "localhost:7001", "localhost:7002"),
)

🎛 Options

Every knob is a functional option, and every one has a resilient default.

client, _ := redis.Connect(ctx,
	redis.WithAddr("localhost:6379"),
	redis.WithPassword("s3cret"),
	redis.WithDB(0),
	redis.WithTLS(&tls.Config{}),
	redis.WithPool(50),
	redis.WithTimeouts(5*time.Second, 3*time.Second, 3*time.Second),
	redis.WithRetry(3, 8*time.Millisecond, 512*time.Millisecond),
)

💓 Health

Healthy is a cheap Ping — wire it straight into a readiness or liveness probe.

if !client.Healthy(ctx) {
	// fail the probe
}

🔌 Logging & metrics

A minimal Logger (dial diagnostics) and Observer (per-command and per-dial signals) are pluggable and default to no-ops, so the core drags in no logging or telemetry dependency.

client, _ := redis.Connect(ctx,
	redis.WithAddr("localhost:6379"),
	redis.WithObserver(myObserver),
)

📊 OpenTelemetry

The optional otel subpackage turns on tracing and metrics in one call against the global providers, keeping the dependency out of the core.

import redisotel "github.com/Bugs5382/go-redis/otel"

client, _ := redis.Connect(ctx, redis.WithAddr("localhost:6379"))
redisotel.Instrument(client) // spans + metrics per command

🛠 Develop

task build    # go build ./...
task test     # go test ./...
task ci       # build + vet + race tests + linters
task license  # verify MIT headers (golic)

Integration tests run against a live server and are excluded from the default build:

REDIS_ADDR=localhost:6379 task test-integration

⚖️ License

MIT © 2026 Shane

Documentation

Overview

Package redis wraps github.com/redis/go-redis/v9 with resilient defaults so a service gets a correctly configured Redis client from a single Connect call: a sensible pool, bounded timeouts, a few retries with backoff, and a startup Ping that verifies readiness. Functional options select a standalone server, a sentinel-managed failover master, or a cluster, and tune pool, timeouts, retries, TLS, and pluggable Logger/Observer hooks. The returned Client exposes the underlying go-redis UniversalClient for the full command API.

Nil, Cmdable, and UniversalClient re-export the handful of go-redis names a caller needs to work with Client.Redis's return value -- the miss sentinel and the command/client interfaces -- so a consumer of this package never needs to import github.com/redis/go-redis/v9 directly.

Index

Examples

Constants

This section is empty.

Variables

View Source
var Nil = goredis.Nil

Nil is the sentinel error go-redis returns when a command finds no result (for example GET on a missing key). It is re-exported here so a caller can write errors.Is(err, redis.Nil) without importing github.com/redis/go-redis/v9 directly.

Functions

This section is empty.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a thin, resilient wrapper over a go-redis UniversalClient. Build one with Connect; use Redis to reach the full go-redis command API, Healthy for a liveness probe, and Close to release the pool. A Client is safe for concurrent use by multiple goroutines.

func Connect

func Connect(ctx context.Context, opts ...Option) (*Client, error)

Connect builds a Redis client from the given options, applies the resilient defaults for anything left unset, and verifies readiness with a Ping before returning. The mode (standalone, sentinel, or cluster) is chosen by the WithAddr, WithSentinel, or WithCluster option; standalone localhost:6379 is the default. On a failed Ping the underlying client is closed and the error is returned, so a returned Client is always usable. The ctx bounds both the dial and the readiness Ping.

Example

Connect to a standalone server with the resilient defaults, then read and write through the underlying go-redis client.

package main

import (
	"context"
	"fmt"
	"log"
	"time"

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

func main() {
	ctx := context.Background()

	client, err := redis.Connect(ctx, redis.WithAddr("localhost:6379"))
	if err != nil {
		log.Fatal(err)
	}
	defer func() { _ = client.Close() }()

	rdb := client.Redis()
	if err := rdb.Set(ctx, "session:123", "alice", time.Minute).Err(); err != nil {
		log.Fatal(err)
	}
	name, err := rdb.Get(ctx, "session:123").Result()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(name)
}
Example (Sentinel)

Connect through Redis Sentinel for high availability: the client discovers the current master through the sentinels and re-resolves it after a failover.

package main

import (
	"context"
	"fmt"
	"log"
	"time"

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

func main() {
	ctx := context.Background()

	client, err := redis.Connect(ctx,
		redis.WithSentinel("mymaster", "localhost:26379", "localhost:26380"),
		redis.WithPassword("s3cret"),
		redis.WithPool(50),
		redis.WithTimeouts(5*time.Second, 3*time.Second, 3*time.Second),
		redis.WithRetry(3, 8*time.Millisecond, 512*time.Millisecond),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer func() { _ = client.Close() }()

	if client.Healthy(ctx) {
		fmt.Println("ready")
	}
}

func (*Client) Close

func (c *Client) Close() error

Close releases the connection pool. It is safe to call once; further use of the Client after Close returns errors from go-redis.

func (*Client) Healthy

func (c *Client) Healthy(ctx context.Context) bool

Healthy reports whether the server answers a Ping within ctx. It is cheap and suitable for readiness and liveness probes.

func (*Client) Redis

func (c *Client) Redis() UniversalClient

Redis returns the underlying client as the UniversalClient alias so callers can use the full command API (Get, Set, pipelines, pub/sub, scripts, and so on) while naming only this package's exported types. The returned value is owned by this Client; do not Close it directly -- use Client.Close.

Example

Name the command surface with this package's own alias -- Cmdable -- and check a miss against the re-exported Nil sentinel. Neither line requires importing github.com/redis/go-redis/v9.

package main

import (
	"context"
	"errors"
	"fmt"
	"log"

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

func main() {
	ctx := context.Background()

	client, err := redis.Connect(ctx, redis.WithAddr("localhost:6379"))
	if err != nil {
		log.Fatal(err)
	}
	defer func() { _ = client.Close() }()

	var cmd redis.Cmdable = client.Redis()
	_, err = cmd.Get(ctx, "session:missing").Result()
	if errors.Is(err, redis.Nil) {
		fmt.Println("cache miss")
	}
}

type Cmdable added in v1.1.0

type Cmdable = goredis.Cmdable

Cmdable is the full go-redis command surface (Get, Set, pipelines, pub/sub, scripts, and so on), re-exported as a type alias so a caller can name it -- for example to store the result of Client.Redis in a typed field or accept it as a function parameter -- without importing github.com/redis/go-redis/v9 directly.

type Logger

type Logger interface {
	// Printf logs a formatted message. ctx carries the call's context, which
	// may hold trace information.
	Printf(ctx context.Context, format string, args ...any)
}

Logger receives connection-level diagnostic messages. Implementations must be safe for concurrent use. The default is a no-op, so the core carries no logging dependency.

type Observer

type Observer interface {
	// ObserveCommand is called after each command completes. name is the Redis
	// command name, dur is how long it took, and err is its result (nil on
	// success; note goredis.Nil signals a missing key, not a failure).
	ObserveCommand(ctx context.Context, name string, dur time.Duration, err error)
	// ObserveDial is called after each attempt to open a new connection.
	ObserveDial(ctx context.Context, network, addr string, dur time.Duration, err error)
}

Observer receives lightweight per-command and per-dial signals, suitable for driving metrics without pulling a telemetry library into the core. Implementations must be safe for concurrent use and must not block. The default is a no-op. For full OpenTelemetry tracing and metrics, use the otel subpackage instead.

type Option

type Option func(*config)

Option configures a Client. Options are applied in order by Connect; a later Option wins over an earlier one.

func WithAddr

func WithAddr(addrs ...string) Option

WithAddr targets a standalone Redis server. The first address is used; extra addresses are ignored (use WithCluster for multiple nodes). Overrides the default localhost:6379.

func WithCluster

func WithCluster(addrs ...string) Option

WithCluster targets a Redis Cluster. addrs are seed node endpoints; the client discovers the rest of the topology and reshards transparently. Note: cluster mode ignores WithDB (Redis Cluster supports only database 0).

func WithDB

func WithDB(db int) Option

WithDB selects the logical database index. Ignored in cluster mode.

func WithLogger

func WithLogger(l Logger) Option

WithLogger installs a Logger for connection-level diagnostics (dial failures). The default is a no-op; the core imposes no logging dependency.

func WithObserver

func WithObserver(o Observer) Option

WithObserver installs an Observer for lightweight command and dial metrics. The default is a no-op; the core imposes no telemetry dependency.

func WithPassword

func WithPassword(password string) Option

WithPassword sets the AUTH password. Leave unset for an unauthenticated server.

func WithPool

func WithPool(size int) Option

WithPool sets the maximum number of socket connections in the pool. A non-positive size is ignored, keeping the resilient default.

func WithRetry

func WithRetry(attempts int, min, max time.Duration) Option

WithRetry tunes command retries: attempts is the maximum number of retries after the first try (mapped to go-redis MaxRetries), and min/max bound the exponential backoff between them. A negative attempts count is ignored; pass 0 to disable retries. Non-positive backoff bounds are left at their defaults.

func WithSentinel

func WithSentinel(masterName string, addrs ...string) Option

WithSentinel targets a Redis Sentinel deployment: masterName is the monitored master's name (commonly "mymaster") and addrs are the sentinel endpoints. This is the high-availability path -- go-redis discovers the current master through the sentinels and re-resolves it after a failover.

func WithTLS

func WithTLS(cfg *tls.Config) Option

WithTLS enables TLS using the given configuration. Pass a non-nil *tls.Config (an empty &tls.Config{} uses the system roots and the server's hostname). A nil config leaves TLS disabled.

func WithTimeouts

func WithTimeouts(dial, read, write time.Duration) Option

WithTimeouts overrides the dial, read, and write timeouts. A non-positive duration for any parameter leaves that timeout at its default.

type UniversalClient added in v1.1.0

type UniversalClient = goredis.UniversalClient

UniversalClient is the client-mode-agnostic go-redis interface (standalone, sentinel-failover, or cluster) that Client wraps, re-exported as a type alias for the same reason as Cmdable. It embeds Cmdable and additionally exposes hooks, transactions, pub/sub, and pool stats.

Directories

Path Synopsis
Package otel adds optional OpenTelemetry tracing and metrics to a go-redis Client in one call.
Package otel adds optional OpenTelemetry tracing and metrics to a go-redis Client in one call.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL