Documentation ¶
Overview ¶
Package cache implements a cache backed by Redis and the official Redis Go client.
Redis Cache provides an implementation of a Cache backed by Redis that handles serialization, compression, and metrics with little to no effort from the user.
Index ¶
- Constants
- Variables
- func IsRetryable(err error) bool
- func MGetValues[T any](ctx context.Context, c *Cache, keys ...string) ([]T, error)
- func Upsert[T any](ctx context.Context, c *Cache, key string, val T, cb UpsertCallback[T]) error
- func UpsertTTL[T any](ctx context.Context, c *Cache, key string, val T, cb UpsertCallback[T], ...) error
- func Version() string
- type Cache
- func (hs *Cache) AddHook(hook Hook)
- func (c *Cache) Client() redis.UniversalClient
- func (c *Cache) Delete(ctx context.Context, keys ...string) error
- func (c *Cache) Expire(ctx context.Context, key string, ttl time.Duration) error
- func (c *Cache) ExtendTTL(ctx context.Context, key string, dur time.Duration) error
- func (c *Cache) Flush(ctx context.Context) error
- func (c *Cache) FlushAsync(ctx context.Context) error
- func (c *Cache) Get(ctx context.Context, key string, v any) error
- func (c *Cache) GetAndExpire(ctx context.Context, key string, v any, ttl time.Duration) error
- func (c *Cache) Healthy(ctx context.Context) bool
- func (c *Cache) Keys(ctx context.Context) ([]string, error)
- func (c *Cache) MSet(ctx context.Context, keyvalues map[string]any) error
- func (c *Cache) MSetWithTTL(ctx context.Context, keyvalues map[string]any, ttl time.Duration) error
- func (c *Cache) ScanKeys(ctx context.Context, pattern string) ([]string, error)
- func (c *Cache) Set(ctx context.Context, key string, v any) error
- func (c *Cache) SetIfAbsent(ctx context.Context, key string, v any, ttl time.Duration) (bool, error)
- func (c *Cache) SetIfPresent(ctx context.Context, key string, v any, ttl time.Duration) (bool, error)
- func (c *Cache) SetWithTTL(ctx context.Context, key string, v any, ttl time.Duration) error
- func (c *Cache) TTL(ctx context.Context, key string) (time.Duration, error)
- type Codec
- type CommandError
- type CommandErrors
- type CompressionHook
- type Hook
- type Marshaller
- type MultiResult
- type Option
- type RedisClient
- type RetryableError
- type Unmarshaller
- type UpsertCallback
Constants ¶
const ( // InfiniteTTL indicates a key will never expire. // // Depending on Redis configuration keys may still be evicted if Redis is // under memory pressure in accordance to the eviction policy configured. InfiniteTTL time.Duration = -3 // KeepTTL indicates to keep the existing TTL on the key on SET commands. KeepTTL = redis.KeepTTL )
Variables ¶
var ( // ErrKeyNotFound is an error value that signals the key requested does not // exist in the cache. ErrKeyNotFound = errors.New("key not found") )
Functions ¶
func IsRetryable ¶ added in v0.5.0
IsRetryable accepts an error and returns a boolean indicating if the operation that generated the error is retryable.
func MGetValues ¶ added in v1.5.3
MGetValues fetches multiple keys from Redis and returns only the values. If the relationship between key -> value is required use MGet instead.
MGetValues is useful when you only want to values and want to avoid the overhead of allocating a slice from a MultiResult.
func Upsert ¶ added in v0.5.0
Upsert retrieves the existing value for a given key and invokes the UpsertCallback. The UpsertCallback function is responsible for determining the value to be stored. The value returned from the UpsertCallback is what is set in Redis.
Upsert allows for atomic updates of existing records, or simply inserting new entries when the key doesn't exist.
Redis uses an optimistic locking model. If the key changes during the transaction Redis will fail the transaction and return an error. However, these errors are retryable. To determine if the error is retryable use the IsRetryable function with the returned error.
cb := rcache.UpsertCallback[Person](func(found bool, oldValue Person, newValue Person) Person { fmt.Println(found) fmt.Println(oldValue) fmt.Println(newValue) return newValue }) retries := 3 for i := 0; i < retries; i++ { err := rcache.Upsert[Person](context.Background(), c, "BillyBob", p, cb) if rcache.IsRetryable(err) { continue } // do something useful ... break }
func UpsertTTL ¶ added in v0.5.0
func UpsertTTL[T any](ctx context.Context, c *Cache, key string, val T, cb UpsertCallback[T], ttl time.Duration) error
UpsertTTL retrieves the existing value for a given key and invokes the UpsertCallback. The UpsertCallback function is responsible for determining the value to be stored. The value returned from the UpsertCallback is what is set in Redis.
Upsert allows for atomic updates of existing records, or simply inserting new entries when the key doesn't exist.
Redis uses an optimistic locking model. If the key changes during the transaction Redis will fail the transaction and return an error. However, these errors are retryable. To determine if the error is retryable use the IsRetryable function with the returned error.
cb := rcache.UpsertCallback[Person](func(found bool, oldValue Person, newValue Person) Person { fmt.Println(found) fmt.Println(oldValue) fmt.Println(newValue) return newValue }) retries := 3 for i := 0; i < retries; i++ { err := rcache.UpsertTTL[Person](context.Background(), c, "BillyBob", p, cb, time.Minute * 1) if rcache.IsRetryable(err) { continue } // do something useful ... break }
Types ¶
type Cache ¶
type Cache struct {
// contains filtered or unexported fields
}
Cache is a simple type that provides basic caching functionality: store, retrieve, and delete. It is backed by Redis and supports storing entries with a TTL.
The zero-value is not usable, and this type should be instantiated using the New function.
func New ¶ added in v1.1.0
func New(client RedisClient, opts ...Option) *Cache
New creates and initializes a new Cache instance.
By default, msgpack is used for marshalling and unmarshalling the entry values. The behavior of Cache can be configured by passing Options.
func NewCache ¶
func NewCache(client RedisClient, opts ...Option) *Cache
NewCache creates and initializes a new Cache instance.
By default, msgpack is used for marshalling and unmarshalling the entry values. The behavior of Cache can be configured by passing Options.
DEPRECATED: NewCache has been deprecated in favor of New and subject to being removed in future versions.
func (*Cache) AddHook ¶ added in v1.1.0
func (hs *Cache) AddHook(hook Hook)
AddHook adds a Hook to the processing chain.
func (*Cache) Client ¶ added in v1.6.0
func (c *Cache) Client() redis.UniversalClient
Client returns the underlying Redis client the Cache is wrapping/using.
This can be useful when there are operations that are not supported by Cache that are required, but you don't want to have to pass the Redis client around your application as well. This allows for the Redis client to be accessed from the Cache. However, it is important to understand that when using the Redis client directly it will not have the same behavior as the Cache. You will have to handle marshalling, unmarshalling, and compression yourself. You will also not have the same hooks behavior as the Cache and some metrics will not be tracked.
func (*Cache) Expire ¶ added in v1.1.0
Expire sets a TTL on the given key.
If the key doesn't exist ErrKeyNotFound will be returned for the error value. If the key already has a TTL it will be overridden with ttl value provided.
Calling Expire with a non-positive ttl will result in the key being deleted.
func (*Cache) ExtendTTL ¶ added in v1.1.0
ExtendTTL extends the TTL for the key by the given duration.
ExtendTTL retrieves the TTL remaining for the key, adds the duration, and then executes the EXPIRE command to set a new TTL.
If the key doesn't exist ErrKeyNotFound will be returned for the error value.
func (*Cache) FlushAsync ¶ added in v0.6.0
FlushAsync flushes the cache deleting all keys/entries asynchronously. Only keys that were present when FLUSH ASYNC command was received by Redis will be deleted. Any keys created during asynchronous flush will be unaffected.
func (*Cache) Get ¶
Get retrieves an entry from the Cache for the given key, and if found will unmarshall the value into v.
If the key does not exist ErrKeyNotFound will be returned as the error value. A non-nil error value will be returned if the operation on the backing Redis fails, or if the value cannot be unmarshalled into the target type.
func (*Cache) GetAndExpire ¶ added in v1.1.0
GetAndExpire retrieves a value from the Cache for the given key, decompresses it if applicable, unmarshalls the value to v, and sets the TTL for the key.
If the key does not exist ErrKeyNotFound will be returned as the error value. A non-nil error value will be returned if the operation on the backing Redis fails, or if the value cannot be unmarshalled into the target type.
Passing a negative ttl value has no effect on the existing TTL for the key. Passing a ttl value of 0 or InfiniteTTL removes the TTL and persist the key until it is either explicitly deleted or evicted according to Redis eviction policy.
func (*Cache) Healthy ¶ added in v1.1.0
Healthy pings Redis to ensure it is reachable and responding. Healthy returns true if Redis successfully responds to the ping, otherwise false.
func (*Cache) MSet ¶ added in v1.2.0
MSet performs multiple SET operations. Entries are added to the cache or overridden if they already exists.
MSet is atomic, either all keyvalues are set or none are set. Since MSet operates using a single atomic command it is the fastest way to bulk write entries to the Cache. It greatly reduces network overhead and latency when compared to calling SET sequentially.
func (*Cache) MSetWithTTL ¶ added in v1.3.0
MSetWithTTL adds or overwrites multiple entries to the cache with a TTL value.
MSetWithTTL performs multiple SET operations using a Pipeline. Unlike MSet, MSetWithTTL is not atomic. It is possible for some entries to succeed while others fail. When the pipeline itself executes successfully but commands fail MSetWithTTL returns CommandErrors which can be inspected to understand which keys failed in the event they need to be retried or logged. If the pipeline execution fails, or marshal and compression fails, a standard error value is returned.
The command errors can be inspected following this example:
err := cache.MSetWithTTL(context.Background(), data, time.Minute*30) if err != nil { var cmdErrs CommandErrors if errors.As(err, &cmdErrs) { for _, e := range cmdErrs { fmt.Println(e) } // todo: do something actually useful here } else { fmt.Println(err) // just a normal error value } }
func (*Cache) ScanKeys ¶ added in v1.4.0
ScanKeys allows for scanning keys in Redis using a pattern.
func (*Cache) Set ¶
Set adds an entry into the cache, or overwrites an entry if the key already existed. The entry is set without an expiration.
func (*Cache) SetIfAbsent ¶ added in v0.3.0
func (c *Cache) SetIfAbsent(ctx context.Context, key string, v any, ttl time.Duration) (bool, error)
SetIfAbsent adds an entry into the cache only if the key doesn't already exist. The entry is set with the provided TTL and automatically removed from the cache once the TTL is expired.
func (*Cache) SetIfPresent ¶ added in v0.3.0
func (c *Cache) SetIfPresent(ctx context.Context, key string, v any, ttl time.Duration) (bool, error)
SetIfPresent updates an entry into the cache if they key already exists in the cache. The entry is set with the provided TTL and automatically removed from the cache once the TTL is expired.
func (*Cache) SetWithTTL ¶
SetWithTTL adds an entry into the cache, or overwrites an entry if the key already existed. The entry is set with the provided TTL and automatically removed from the cache once the TTL is expired.
type Codec ¶ added in v1.0.0
Codec is an interface type that defines the behavior for compressing and decompressing data.
type CommandError ¶ added in v1.3.0
func (CommandError) Error ¶ added in v1.3.0
func (r CommandError) Error() string
type CommandErrors ¶ added in v1.3.0
type CommandErrors []CommandError
func (CommandErrors) Error ¶ added in v1.3.0
func (r CommandErrors) Error() string
func (CommandErrors) Keys ¶ added in v1.3.0
func (r CommandErrors) Keys() []string
type CompressionHook ¶ added in v1.1.0
CompressionHook is a function type that is invoked prior to compressing or decompressing data.
type Hook ¶ added in v1.1.0
type Hook interface { MarshalHook(next Marshaller) Marshaller UnmarshallHook(next Unmarshaller) Unmarshaller CompressHook(next CompressionHook) CompressionHook DecompressHook(next CompressionHook) CompressionHook }
Hook is an interface type defining the operations that can be intercepted and potentially allow for their behavior to be modified.
The primary intention of Hook is to allow for observability: instrumentation, logging, tracing, etc.
It is important implementations of Hook call next or the execution pipeline will terminate.
type Marshaller ¶
Marshaller is a function type that marshals the value of a cache entry for storage.
func DefaultMarshaller ¶
func DefaultMarshaller() Marshaller
DefaultMarshaller returns a Marshaller using msgpack to marshall values.
type MultiResult ¶ added in v0.2.0
MultiResult is a type representing returning multiple entries from the Cache.
func MGet ¶ added in v0.2.0
MGet uses the provided Cache to retrieve multiple keys from Redis and returns a MultiResult.
If a key doesn't exist in Redis it will not be included in the MultiResult returned. If all keys are not found the MultiResult will be empty.
func Scan ¶ added in v1.5.0
Scan retrieves all the keys and values from Redis matching the given pattern.
Scan works similar to MGet, but allows a pattern to be specified rather than providing keys.
func (MultiResult[T]) Get ¶ added in v0.2.0
func (mr MultiResult[T]) Get(key string) (T, bool)
Get returns the value and a boolean indicating if the key exists. If the key doesn't exist the value will be the default zero value.
func (MultiResult[T]) IsEmpty ¶ added in v0.2.0
func (mr MultiResult[T]) IsEmpty() bool
IsEmpty returns a boolean indicating if the results are empty.
func (MultiResult[T]) Keys ¶ added in v0.2.0
func (mr MultiResult[T]) Keys() []string
Keys returns all the keys found.
func (MultiResult[T]) Values ¶ added in v0.2.0
func (mr MultiResult[T]) Values() []T
Values returns all the values found.
type Option ¶
type Option func(c *Cache)
Option allows for the Cache behavior/configuration to be customized.
func BatchMultiGets ¶ added in v1.6.0
BatchMultiGets configures the Cache to use pipelining and split keys up into multiple MGET commands for increased throughput and lower latency when dealing with MGet operations with very large sets of keys.
func Brotli ¶ added in v1.1.0
func Brotli() Option
Brotli configures the Cache to use Brotli for compressing and decompressing values stored in Redis. The default Brotli configuration uses a balanced approach between speed and compression level.
func Compression ¶ added in v1.0.0
Compression allows for the values to be flated and deflated to conserve bandwidth and memory at the cost of higher CPU time. Compression accepts a Codec to handle compressing and decompressing the data to/from Redis.
func Flate ¶ added in v1.0.0
func Flate() Option
Flate configures the Cache to use Flate Codec for compressing and decompressing values stored in Redis. Flate uses a default configuration favoring compression over speed.
func GZip ¶ added in v1.0.0
func GZip() Option
GZip configures the Cache to use gzip for compressing and decompressing values stored in Redis. GZip uses a default configuration favoring compression size over speed
func JSON ¶ added in v1.1.0
func JSON() Option
JSON is a convenient Option for configuring Cache to use JSON for serializing data stored in the cache.
JSON is the equivalent of using Serialization passing it a Marshaller and Unmarshaller using json.
func LZ4 ¶ added in v1.0.0
func LZ4() Option
LZ4 configures the Cache to use lz4 for compressing and decompressing values stored in Redis.
func Serialization ¶
func Serialization(mar Marshaller, unmar Unmarshaller) Option
Serialization allows for the marshalling and unmarshalling behavior to be customized for the Cache.
A valid Marshaller and Unmarshaller must be provided. Providing nil for either will immediately panic.
type RedisClient ¶ added in v0.3.0
type RedisClient interface { Get(ctx context.Context, key string) *redis.StringCmd GetEx(ctx context.Context, key string, expiration time.Duration) *redis.StringCmd MGet(ctx context.Context, keys ...string) *redis.SliceCmd Set(ctx context.Context, key string, val any, ttl time.Duration) *redis.StatusCmd SetNX(ctx context.Context, key string, value any, expiration time.Duration) *redis.BoolCmd SetXX(ctx context.Context, key string, value any, expiration time.Duration) *redis.BoolCmd MSet(ctx context.Context, values ...any) *redis.StatusCmd Del(ctx context.Context, keys ...string) *redis.IntCmd Watch(ctx context.Context, fn func(*redis.Tx) error, keys ...string) error Scan(ctx context.Context, cursor uint64, match string, count int64) *redis.ScanCmd FlushDB(ctx context.Context) *redis.StatusCmd FlushDBAsync(ctx context.Context) *redis.StatusCmd Ping(ctx context.Context) *redis.StatusCmd TTL(ctx context.Context, key string) *redis.DurationCmd Expire(ctx context.Context, key string, expiration time.Duration) *redis.BoolCmd Pipeline() redis.Pipeliner }
RedisClient is an interface type that defines the Redis functionality this package requires to use Redis as a cache.
type RetryableError ¶ added in v0.5.0
type RetryableError struct {
// contains filtered or unexported fields
}
func (RetryableError) Error ¶ added in v0.5.0
func (e RetryableError) Error() string
func (RetryableError) IsRetryable ¶ added in v0.5.0
func (e RetryableError) IsRetryable() bool
type Unmarshaller ¶
Unmarshaller is a function type that unmarshalls the value retrieved from the cache into the target type.
func DefaultUnmarshaller ¶
func DefaultUnmarshaller() Unmarshaller
DefaultUnmarshaller returns an Unmarshaller using msgpack to unmarshall values.
type UpsertCallback ¶ added in v0.5.0
UpsertCallback is a callback function that is invoked by Upsert. An UpsertCallback is passed if a key was found, the old value (or zero-value if the key wasn't found) and the new value. An UpsertCallback is responsible for determining what value should be set for a given key in the cache. The value returned from UpsertCallback is the value set.