Documentation ¶
Overview ¶
Package cache implements a cache backed by Redis and the Rueidis Redis Go client.
Rueidis 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 Cacheable[T any](ctx context.Context, c *Cache, key string, readTimeout time.Duration, ...) (T, error)
- func Delete[T any](ctx context.Context, c *Cache, key string, val T, ...) error
- 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 Version() string
- func Write[T any](ctx context.Context, c *Cache, key string, val T, ttl time.Duration, ...) error
- type Cache
- func (hs *Cache) AddHook(hook Hook)
- func (c *Cache) Client() rueidis.Client
- 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) GetAndUpdateTTL(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) ScanKeys(ctx context.Context, pattern string) ([]string, error)
- func (c *Cache) Set(ctx context.Context, key string, v any, ttl time.Duration) error
- func (c *Cache) SetClient(client rueidis.Client)
- 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) TTL(ctx context.Context, key string) (time.Duration, error)
- type Codec
- type CompressionHook
- type Hook
- type Marshaller
- type MultiResult
- type Option
- 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 )
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 Cacheable ¶
func Cacheable[T any]( ctx context.Context, c *Cache, key string, readTimeout time.Duration, ttl time.Duration, fn func(ctx context.Context) (T, error)) (T, error)
Cacheable attempts to read a value from the cache for a given key. On a cache miss or read error, it executes the provided function (fn) to retrieve or compute the value. If successful, the value is then asynchronously stored in the cache with the specified TTL (time-to-live) for future requests.
This function implements a read-through cache pattern, where the cache is updated after a cache miss. Cacheable only returns an error if the value cannot be retrieved or computed by the provided function.
Errors encountered while storing the value in the cache are logged, but not returned to the caller, and the cache set operation occurs in a non-blocking goroutine.
The cache read operation is subject to a readTimeout, which defines the maximum duration for waiting on a cache response. If the cache read exceeds this timeout or fails, the provided function is called to compute the value.
func Delete ¶
func Delete[T any]( ctx context.Context, c *Cache, key string, val T, fn func(ctx context.Context, val T) error) error
Delete removes the value associated with the given key from both the source of truth and the cache. It first attempts to delete the value from the source of truth using the provided function. If this operation is successful, it then removes the corresponding entry from the cache.
Delete is designed to ensure that both the source of truth and the cache remain in sync. If the source of truth is updated but the cache is not, the system may end up in an inconsistent state. Therefore, it is essential to call this function whenever a value needs to be deleted from both the source of truth and the cache.
If either the delete operation from the source of truth or the cache fails, an error is returned, providing information on where the failure occurred.
func IsRetryable ¶
IsRetryable accepts an error and returns a boolean indicating if the operation that generated the error is retryable.
func MGetValues ¶
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 ¶
func Upsert[T any](ctx context.Context, c *Cache, key string, val T, cb UpsertCallback[T], ttl time.Duration) error
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, time.Minute * 1) if rcache.IsRetryable(err) { continue } // do something useful ... break }
func Write ¶
func Write[T any]( ctx context.Context, c *Cache, key string, val T, ttl time.Duration, fn func(ctx context.Context, v T) error) error
Write first invokes the provided function to write the value to the source of truth. If the write operation is successful, the value is then synchronously stored in the cache with the specified TTL (time-to-live) for future requests.
Write implements a write-through cache pattern, where the cache is updated after the source of truth is updated. Write is NOT atomic. It is possible that the source of truth is updated but the cache is not. This is a trade-off for the performance benefits of write-through caching. If either write operation fails, an error is returned.
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 ¶
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 (*Cache) AddHook ¶
func (hs *Cache) AddHook(hook Hook)
AddHook adds a Hook to the processing chain.
func (*Cache) Client ¶
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 ¶
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 ¶
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 ¶
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) GetAndUpdateTTL ¶
GetAndUpdateTTL retrieves a value from the Cache for the given key, decompresses it if applicable, unmarshalls the value to v, and updates 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.
The TTL/expiration for the key is updated to the provided key if it exists, even if the key did not have a TTL previously. If the ttl value is <= 0 the key will be persisted indefinitely.
func (*Cache) Healthy ¶
Healthy pings Redis to ensure it is reachable and responding. Healthy returns true if Redis successfully responds to the ping, otherwise false.
Note that Healthy does not guarantee that Redis is fully operational, only that it is reachable and responding to pings.
func (*Cache) MSet ¶
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) Set ¶
Set adds an entry into the cache, or overwrites an entry if the key already existed. If the ttl value is <= 0 the key will be persisted indefinitely.
func (*Cache) SetClient ¶
SetClient sets the underlying Redis client the Cache is wrapping/using.
Passing nil is not permitted and will result in a panic.
func (*Cache) SetIfAbsent ¶
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. If the ttl value is <= 0 the key will be persisted indefinitely.
func (*Cache) SetIfPresent ¶
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. If the ttl value is <= 0 the key will be persisted indefinitely.
type Codec ¶
Codec is an interface type that defines the behavior for compressing and decompressing data.
type CompressionHook ¶
CompressionHook is a function type that is invoked prior to compressing or decompressing data.
type Hook ¶
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 ¶
MultiResult is a type representing returning multiple entries from the Cache.
func MGet ¶
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 ¶
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 ¶
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 ¶
func (mr MultiResult[T]) IsEmpty() bool
IsEmpty returns a boolean indicating if the results are empty.
func (MultiResult[T]) Keys ¶
func (mr MultiResult[T]) Keys() []string
Keys returns all the keys found.
func (MultiResult[T]) Values ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
func LZ4() Option
LZ4 configures the Cache to use lz4 for compressing and decompressing values stored in Redis.
func NearCache ¶
NearCache enables a local in-memory cache to reduce the load on Redis and improve the latency.
Providing a TTL <=0 is a no-op.
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 RetryableError ¶
type RetryableError struct {
// contains filtered or unexported fields
}
func (RetryableError) Error ¶
func (e RetryableError) Error() string
func (RetryableError) IsRetryable ¶
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 ¶
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.