redis

redis wraps go-redis for key/value storage, Pub/Sub messaging, typed payload encoding, and connection health checks.

Part of nurago, a collection of independent Go packages for backend services.

import "github.com/tecnickcom/nurago/pkg/redis"

Package redis wraps go-redis for key/value storage, Pub/Sub messaging, typed payload encoding, and connection health checks.

Redis reference: https://redis.io Underlying client: https://github.com/redis/go-redis

How It Works

New creates a Client given a SrvOptions (aliased from go-redis Options) and a variadic list of Option values:

  1. The server address is validated before any network connection is attempted (skipped when a client is injected via WithRedisClient, since no connection is dialed). Both TCP host:port addresses and unix domain sockets are supported.
  2. A go-redis client is constructed (or injected via WithRedisClient for tests). When at least one channel is declared with WithChannels, a Pub/Sub subscription feeds Client.Receive and Client.ReceiveData one message per call. The subscription runs until Client.Close is called: canceling the New context does not stop it.
  3. Encode and decode functions (defaulting to DefaultMessageEncodeFunc and DefaultMessageDecodeFunc) are stored on the client and used transparently by the typed data methods.

Operations

  • Client.Set, Client.Get, and Client.Del provide raw key/value access with expiration.
  • Client.SetData and Client.GetData encode and decode Go values with the configured TEncodeFunc and TDecodeFunc.
  • Client.Send and Client.Receive carry raw strings; Client.SendData and Client.ReceiveData apply the same codec and return the channel name with the decoded value.
  • WithMessageEncodeFunc and WithMessageDecodeFunc replace the default codec.
  • Client.HealthCheck sends a PING and returns a wrapped error on failure.
  • A missing key surfaces as ErrKeyNotFound; other configuration and subscription states surface as the exported Err values, all matchable with errors.Is.
  • WithRedisClient injects a custom RClient for testing.
  • Client.Close releases Pub/Sub and client resources; it is idempotent and required to stop the subscription when channels are configured.

Subscription Configuration

Use options to define Pub/Sub behavior at client creation time:

  • WithChannels to subscribe to channels.
  • WithChannelOptions to tune subscription channel behavior: buffer size, send timeout, and health check interval. With the go-redis defaults, a consumer that stops calling Client.Receive loses messages once the 100-message buffer stays full for one minute.

Usage

srv := &redis.SrvOptions{Addr: "localhost:6379"}

c, err := redis.New(ctx, srv, redis.WithChannels("events"))
if err != nil {
    return err
}
defer c.Close()

if err := c.Set(ctx, "k", "v", 0); err != nil {
    return err
}

if err := c.SendData(ctx, "events", event); err != nil {
    return err
}

var event Event

channel, err := c.ReceiveData(ctx, &event)
if err != nil {
    return err
}

if err := c.HealthCheck(ctx); err != nil {
    return err
}

To swap in an encrypted codec, supply custom functions at construction time:

c, err := redis.New(ctx, srv,
    redis.WithMessageEncodeFunc(myEncryptAndEncode),
    redis.WithMessageDecodeFunc(myDecryptAndDecode),
)

When To Use

  • You store structs and want serialization handled rather than written per call site.
  • The same client should serve caching and Pub/Sub.
  • Redis must be reported on the service health endpoint.

Example

client, err := redis.New(
	context.TODO(),
	nil,
	redis.WithRedisClient(&exampleRClient{data: make(map[string]string)}),
)
if err != nil {
	fmt.Println(err)

	return
}

defer func() { _ = client.Close() }()

ctx := context.TODO()

err = client.Set(ctx, "greeting", "hello", time.Minute)
if err != nil {
	fmt.Println(err)

	return
}

var value string

err = client.Get(ctx, "greeting", &value)

fmt.Println(value, err)

fmt.Println(client.Del(ctx, "greeting"))

// Output:
// hello <nil>
// <nil>

Full source is in example_redis_test.go. More runnable examples are on pkg.go.dev.

Dependencies

Importing this package pulls 4 external modules:

  • github.com/cespare/xxhash/v2
  • github.com/redis/go-redis/v9
  • go.uber.org/atomic
  • golang.org/x/sys