redis

package
v2.46.1 Latest Latest
Warning

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

Go to latest
Published: Sep 14, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package redis provides an instrumented Redis client that implements app.Component.

The client wraps go-redis and supports single-node, Sentinel, and Cluster topologies through a unified Config. OpenTelemetry tracing and Prometheus metrics are applied as hooks at construction time and require no changes to call sites.

Use Client.Redis to obtain the underlying goredis.UniversalClient for executing commands.

Basic usage

client, err := redis.NewWithConfig(&redis.Config{
    Addrs: []string{"localhost:6379"},
})
if err != nil { log.Fatal(err) }

a.Register(client)
if err := a.Start(ctx); err != nil { log.Fatal(err) }
defer a.Shutdown(ctx) //nolint:errcheck

val, err := client.Redis().Get(ctx, "my-key").Result()

With tracing and metrics

client, err := redis.NewWithConfig(&redis.Config{
    Addrs:      []string{"localhost:6379"},
    Tracer:     a.Tracer(),
    Registerer: a.Metrics().Registerer(),
})

Every command automatically receives an OpenTelemetry span and is counted in Prometheus histograms.

Sentinel (high-availability)

client, err := redis.NewWithConfig(&redis.Config{
    Addrs:      []string{"sentinel1:26379", "sentinel2:26379"},
    MasterName: "mymaster",
})

In security-hardened deployments Sentinel processes require their own credentials, distinct from the Redis data-tier credentials:

client, err := redis.NewWithConfig(&redis.Config{
    Addrs:            []string{"sentinel1:26379", "sentinel2:26379"},
    MasterName:       "mymaster",
    SentinelUsername: "sentinel-user",
    SentinelPassword: "sentinel-secret",
    Password:         "redis-secret",
})

Cluster

client, err := redis.NewWithConfig(&redis.Config{
    Addrs: []string{"node1:6379", "node2:6379", "node3:6379"},
})

Reading configuration from Kubernetes

In Kubernetes deployments, New reads the Redis connection parameters from the infrastructure configuration mounted by the platform (typically via infrastructure.DefaultConfig). Authentication credentials and TLS material are resolved from infrastructure.Config.Secrets and infrastructure.Config.TLSSecrets. Secrets are looked up under the "redis/" prefix.

The format field on infrapb.Redis.SecretRef controls how credential keys are mapped inside the referenced Kubernetes Secret:

  • REDIS_FORMAT_VALKEY — uses a fixed preset that matches the Secret produced by the valkey/valkey Helm chart. Only the password is read, from the key `default-password`, for the `default` ACL user. Username and Sentinel credentials are ignored.
  • REDIS_FORMAT_CUSTOM — reads the key names from infrapb.RedisSecret.Projection. Each non-nil field in the projection names the Secret key for that credential (username, password, sentinel_username, sentinel_password).

For REDIS_FORMAT_CUSTOM, leaving a projection field nil means that credential is not read from the Secret. A nil password or sentinel_password means the connection is unauthenticated but we want to read the username and/or the sentinel_username field. A non-nil field that points to a key absent from the Secret returns an error.

TLS material is read from the fixed keys regardless of the projection:

  • redis/tls.crt — client TLS certificate (PEM)
  • redis/tls.key — client TLS private key (PEM)
  • redis/ca.crt — CA certificate for server verification (PEM)

Any secret.Provider that resolves these slash-separated keys serves them, such as the secret.FileProvider the infrastructure package roots at the mounted TLS secrets directory.

client, err := redis.New(ctx)
if errors.Is(err, infrastructure.ErrNotConfigured) {
    // Redis is not configured in this environment; skip or use a default.
}

Overriding configuration when reading from Kubernetes

New accepts functional options that let callers override specific aspects of the configuration derived from the infrastructure config. Authentication and topology fields (Addrs, MasterName, SentinelUsername, SentinelPassword, Username, Password, DB, TLSConfig) are always sourced from the infrastructure config and its secret providers; they cannot be overridden via WithClientConfig.

Use WithClientConfig to override connection-pool, timeout, retry, and naming fields:

client, err := redis.New(ctx,
    redis.WithClientConfig(&redis.Config{
        DialTimeout:     500 * time.Millisecond,
        ReadTimeout:     1 * time.Second,
        WriteTimeout:    1 * time.Second,
        PoolSize:        20,
        MinIdleConns:    5,
        MaxIdleConns:    10,
        PoolTimeout:     2 * time.Second,
        ConnMaxIdleTime: 5 * time.Minute,
        ConnMaxLifetime: 30 * time.Minute,
        MaxRetries:      3,
        MinRetryBackoff: 8 * time.Millisecond,
        MaxRetryBackoff: 512 * time.Millisecond,
        Name:            "cache",
        Namespace:       "myservice",
        Subsystem:       "redis",
    }),
)

Use WithLogger, WithRegisterer, and WithTracer to attach observability dependencies sourced from the application's app.App:

client, err := redis.New(ctx,
    redis.WithLogger(a.Logger()),
    redis.WithRegisterer(a.Metrics().Registerer()),
    redis.WithTracer(a.Tracer()),
)

Connection parameters for another client library

The rules above, which Secret keys the secret_ref format maps each credential to, addresses read from the contract or from the Secret, inline values winning over the Secret, and the TLS configuration assembled from the mounted files, live in this package. A service that keeps its own client library, for example rueidis for pub/sub and transactions, would otherwise have to reimplement them. ConnectionParams applies the same rules New does and returns the resolved Params without constructing a client:

infra, err := infrastructure.DefaultConfig()
if err != nil {
	log.Fatal(err)
}

params, err := redis.ConnectionParams(ctx, infra)
if err != nil {
	log.Fatal(err)
}

// params.Addrs, params.MasterName, params.Username, params.Password,
// params.SentinelUsername, params.SentinelPassword, params.DB and
// params.TLSConfig feed the service's own client.

Params.Password and Params.SentinelPassword are secret.Secret values and redact themselves when printed.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrMissingSecrets          = errors.New("secret provider missing")
	ErrUnknownSecretFormat     = errors.New("unknown secret format")
	ErrSecretProjectionMissing = errors.New("secret projection missing")
	ErrEmptyAddresses          = errors.New("address list is empty")
)

Functions

This section is empty.

Types

type Client

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

Client is an instrumented Redis client that implements app.Component. Call [Start] to verify connectivity and [Shutdown] to close all connections.

Client.Redis returns the underlying goredis.UniversalClient, which supports single-node, Sentinel, and Cluster topologies through a single consistent interface.

func New added in v2.15.0

func New(ctx context.Context, opts ...NewOption) (*Client, error)

New returns a Client configured from environment variables, reading the infrastructure configuration from the standard config path.

Returns infrastructure.ErrNotConfigured when no Redis config is present.

func NewWithConfig

func NewWithConfig(cfg *Config) (*Client, error)

NewWithConfig returns a Client configured with cfg. The underlying go-redis connection is lazy: no network calls are made until [Start] or the first command is executed.

OTel tracing, Prometheus metrics, and structured logging hooks are registered at construction time when the corresponding Config fields are non-nil.

func (*Client) Name

func (c *Client) Name() string

Name returns the component name for use in logs and error messages.

func (*Client) Redis

func (c *Client) Redis() goredis.UniversalClient

Redis returns the underlying goredis.UniversalClient for executing commands. The client is safe to use before [Start] — go-redis connects lazily — but [Start] should be called during application startup to verify connectivity before serving traffic.

func (*Client) Shutdown

func (c *Client) Shutdown(ctx context.Context) error

Shutdown closes the Redis connection and releases all resources. It satisfies app.Component and should be called via app.App.Shutdown.

func (*Client) Start

func (c *Client) Start(ctx context.Context) error

Start pings the Redis server to verify connectivity. It satisfies app.Component and should be called via app.App.Start.

type Config

type Config struct {
	// Addrs is one or more Redis server addresses.
	//   Single-node:  []string{"localhost:6379"}
	//   Cluster:      multiple node addresses
	//   Sentinel:     sentinel addresses (also set MasterName)
	// Required: NewWithConfig returns an error if Addrs is empty.
	Addrs []string

	// MasterName is the Redis Sentinel master name.
	// Setting this enables Sentinel (failover) mode.
	MasterName string

	// SentinelUsername is the ACL username for authenticating to Sentinel
	// processes. Only applies when MasterName is set. Leave empty to use
	// the default user.
	SentinelUsername string

	// SentinelPassword is the AUTH password for Sentinel processes.
	// Only applies when MasterName is set. This is distinct from Password,
	// which authenticates to the Redis data nodes.
	SentinelPassword string

	// Username is the Redis ACL username (Redis 6+). Leave empty when using
	// the default user.
	Username string

	// Password is the Redis AUTH password.
	Password string

	// DB is the logical database number. Only applies to single-node and
	// Sentinel modes; ignored for Cluster. Defaults to 0.
	DB int

	// DialTimeout is the timeout for establishing new connections.
	// Defaults to the go-redis default (5s).
	DialTimeout time.Duration

	// ReadTimeout is the timeout for socket reads. Use -1 to disable.
	// Defaults to the go-redis default (3s).
	ReadTimeout time.Duration

	// WriteTimeout is the timeout for socket writes. Use -1 to disable.
	// Defaults to ReadTimeout.
	WriteTimeout time.Duration

	// PoolSize is the maximum number of connections in the pool per node.
	// Defaults to the go-redis default (10 * runtime.NumCPU()).
	PoolSize int

	// MinIdleConns is the minimum number of idle connections to keep open.
	// Use this to pre-warm the pool at startup and avoid cold-start latency
	// on the first burst of requests.
	MinIdleConns int

	// MaxIdleConns is the maximum number of idle connections retained in the
	// pool. Zero means no limit.
	MaxIdleConns int

	// PoolTimeout is how long to wait for an available connection when the
	// pool is exhausted. Defaults to ReadTimeout + 1s.
	PoolTimeout time.Duration

	// ConnMaxIdleTime is the maximum duration a connection may sit idle
	// before being closed. Defaults to the go-redis default (30 minutes).
	// Set to -1 to disable idle timeout.
	ConnMaxIdleTime time.Duration

	// ConnMaxLifetime is the maximum duration a connection may be reused
	// before being closed. Zero means no limit.
	ConnMaxLifetime time.Duration

	// MaxRetries is the maximum number of retries before giving up on a
	// command. Defaults to the go-redis default (3 retries).
	// Set to -1 to disable retries.
	MaxRetries int

	// MinRetryBackoff is the minimum backoff between retries.
	// Defaults to the go-redis default (8ms). Set to -1 to disable backoff.
	MinRetryBackoff time.Duration

	// MaxRetryBackoff is the maximum backoff between retries.
	// Defaults to the go-redis default (512ms). Set to -1 to disable backoff.
	MaxRetryBackoff time.Duration

	// TLSConfig enables TLS for all connections when set. Uses the standard
	// crypto/tls.Config; see https://pkg.go.dev/crypto/tls#Config.
	TLSConfig *tls.Config

	// Name identifies this client in logs, errors, and as a constant label on
	// all Prometheus metrics. Defaults to "redis".
	//
	// Each client registered against the same Registerer must have a distinct
	// Name. Reusing a name causes NewWithConfig to return an error, because
	// sharing metric descriptors would silently drop pool stats and aggregate
	// command metrics across logically distinct clients.
	Name string

	// Namespace is the Prometheus metric namespace prepended to every metric
	// name. Defaults to "gitlab".
	Namespace string

	// Subsystem is the Prometheus metric subsystem. Defaults to "redis".
	// Together with Namespace this produces names of the form
	// gitlab_redis_command_duration_seconds.
	Subsystem string

	// Tracer enables OpenTelemetry span recording per command.
	// When nil, tracing is disabled.
	Tracer *trace.Tracer

	// Registerer is the Prometheus registerer used to publish Redis metrics.
	// When nil, Prometheus metrics are not collected.
	Registerer prometheus.Registerer

	// Logger is used for structured log entries per command and pipeline. When
	// nil, no log output is produced. The client name is automatically included
	// on every entry — callers do not need to set it manually.
	Logger *slog.Logger

	// DisableClientCommands suppresses CLIENT SETINFO, CLIENT SETNAME and CLIENT MAINT_NOTIFICATIONS on connect
	DisableClientCommands *bool
}

Config holds optional configuration for NewWithConfig.

type NewOption added in v2.15.0

type NewOption func(*clientOptions)

NewOption configures a Client created via New.

func WithClientConfig added in v2.15.0

func WithClientConfig(c *Config) NewOption

WithClientConfig sets the Config used to configure the Redis client. Note that only the non-infrastructure fields are overridden by the client config. Fields that are explicitly set in the client config take precedence over fields that would otherwise be derived from the infrastructure configuration.

func WithInfraConfig added in v2.15.0

func WithInfraConfig(c *infrastructure.Config) NewOption

WithInfraConfig sets the infrastructure.Config used to read infrastructure configuration and secrets. When nil, the default config is used.

func WithLogger added in v2.15.0

func WithLogger(l *slog.Logger) NewOption

WithLogger sets the *slog.Logger used to emit structured log entries per command and pipeline. When nil, no log output is produced.

func WithRegisterer added in v2.15.0

func WithRegisterer(r prometheus.Registerer) NewOption

WithRegisterer sets the prometheus.Registerer used to publish Redis metrics.

func WithTracer added in v2.15.0

func WithTracer(t *trace.Tracer) NewOption

WithTracer sets the trace.Tracer used to instrument Redis commands.

type Params added in v2.46.0

type Params struct {
	Addrs            []string
	MasterName       string
	SentinelUsername string
	SentinelPassword secret.Secret
	Username         string
	Password         secret.Secret
	DB               int
	TLSConfig        *tls.Config
}

Params are the connection parameters the infrastructure contract resolves to for its Redis entry. The fields mirror the connection fields of Config. Params may gain fields in later versions.

Credentials are empty when the contract declares no secret_ref, which expresses an unauthenticated connection, or when the secret_ref format does not project them. TLSConfig is nil when no TLS material is mounted.

func ConnectionParams added in v2.46.0

func ConnectionParams(ctx context.Context, infra *infrastructure.Config, opts ...ParamsOption) (Params, error)

ConnectionParams resolves the Redis entry of the infrastructure contract to connection parameters without constructing a client.

The caller loads the contract first, with infrastructure.DefaultConfig or infrastructure.Load. ConnectionParams exists for services that keep their own client library and would otherwise reimplement the contract's rules, which are the ones New applies: the addresses come from the contract or, when it lists none, from the Secret key the CUSTOM projection names; credentials are read from the Secret keys named by the secret_ref format (the VALKEY preset or a CUSTOM projection), with an inline username winning over the Secret and a credential the format does not project left empty; and the TLS configuration is assembled from whichever of the tls.crt, tls.key and ca.crt files of the mounted TLS Secret exist.

Errors wrap infrastructure.ErrNotConfigured for a nil infra or a contract without a Redis entry, ErrMissingSecrets for a secret_ref without a secret provider, an error matching both ErrSecretProjectionMissing and secret.ErrProjectionMissing for format REDIS_FORMAT_CUSTOM without a projection, ErrUnknownSecretFormat, ErrEmptyAddresses for an address list, inline or projected, without an address, secret.ErrNotFound for a projected key the Secret does not hold, secret.ErrProjectionMissing for addresses neither listed nor projected, secret.ErrProjectionInvalid, an error from parsing the TLS material, or any other error the secret provider returns. Several may be joined.

type ParamsOption added in v2.46.0

type ParamsOption func(*paramsOptions)

ParamsOption configures ConnectionParams. No options exist yet; the type keeps the signature open for them.

Jump to

Keyboard shortcuts

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