Documentation
¶
Overview ¶
Package cachecfg selects and builds a cache.Cache[T] from configuration: either the in-process memory cache or Redis.
There is deliberately no default provider. Whether a cache lives in this process or in Redis is a fact about a deployment rather than something a library can pick, so an unset Provider fails validation instead of quietly becoming a memory cache. Several fields — MaxEntries, EvictionPolicy, JanitorInterval — are read only by the memory provider, which is the only one holding entries in this process's heap.
Index ¶
Constants ¶
const ( // ProviderMemory is the memory provider. ProviderMemory = "memory" // ProviderRedis is the redis provider. ProviderRedis = "redis" )
Variables ¶
This section is empty.
Functions ¶
func NewCache ¶
NewCache provides a Cache.
Each provider is built into a variable and returned only once its error is known to be nil, rather than returned straight from the constructor. The provider constructors return their own concrete types, so `return memory.NewInMemoryCache[T](...)` would convert a nil *memory.Cache[T] into a non-nil cache.Cache[T] on the error path, and a caller testing the returned interface against nil would find a cache that panics on first use.
Types ¶
type Config ¶
type Config struct {
Redis *redis.Config `env:",init" envPrefix:"REDIS_" json:"redis,omitempty" yaml:"redis,omitempty"`
Provider string `env:"PROVIDER" json:"provider,omitempty" yaml:"provider,omitempty"`
// EvictionPolicy names which entry the memory provider drops once
// MaxEntries is reached: "least_recently_used" (alias "lru") or
// "oldest_written" (alias "fifo"). It is read only when MaxEntries is
// positive, so the default here costs an unbounded cache nothing.
EvictionPolicy string `env:"EVICTION_POLICY" envDefault:"least_recently_used" json:"evictionPolicy,omitempty" yaml:"evictionPolicy,omitempty"`
CircuitBreaker circuitbreakingcfg.Config `` /* 129-byte string literal not displayed */
// Expiry is the default expiry for writes that don't specify one via
// cache.WithExpiry; a non-positive value means entries never expire by
// default.
Expiry time.Duration `env:"EXPIRY" envDefault:"1h" json:"expiry,omitempty" yaml:"expiry,omitempty"`
// JanitorInterval is how often the memory provider sweeps expired
// entries. It is ignored by every other provider, which expire entries
// in the backing store rather than in this process. A non-positive
// value disables the sweep, leaving the memory provider's lazy
// eviction as the only reclaim path — see memory.WithJanitor for why
// that is rarely what a long-lived cache wants.
JanitorInterval time.Duration `env:"JANITOR_INTERVAL" envDefault:"5m" json:"janitorInterval,omitempty" yaml:"janitorInterval,omitempty"`
// MaxEntries bounds how many entries the memory provider holds,
// dropping one per EvictionPolicy whenever a write would exceed it. It
// is ignored by every other provider, which bound their own storage.
// A non-positive value leaves the cache bounded only by expiry — see
// memory.WithMaxEntries for when that is not enough.
MaxEntries int `env:"MAX_ENTRIES" json:"maxEntries,omitempty" yaml:"maxEntries,omitempty"`
}
Config is the configuration for the cache.
func (*Config) ValidateWithContext ¶
ValidateWithContext validates a Config struct.
The sub-config for a provider that was not selected is skipped rather than merely unguarded: ozzo validates any non-nil pointer to a Validatable once a field's rules have run, and `env:",init"` leaves every sub-config non-nil. A validation.When guard alone stops the Required rule and nothing else, so Redis' own rules were enforced and the memory provider could not load.
type Option ¶
type Option func(*options)
Option configures how NewCache assembles its cache.
The observability dependencies are options rather than parameters because every one of them is genuinely optional: an absent logger logs nowhere, an absent tracer provider traces nowhere, and an absent metrics provider records nothing. Requiring them positionally made a caller that wanted none of the three name all three anyway, usually as noops.
It carries no type parameter even though NewCache does. Go cannot infer a type argument from a call's result type, so an Option[T] would force every call site to spell the cached type out by hand — WithLogger[MyValue](l) — forever.
func WithLogger ¶
WithLogger attaches a logger. An absent logger logs nowhere.
func WithMetricsProvider ¶
WithMetricsProvider attaches a metrics provider for the cache's counters and latency histogram. An absent provider records nothing.
func WithPillars ¶
func WithPillars(p *observability.Pillars) Option
WithPillars attaches a logger, tracer provider, and metrics provider in one go, for the common case where a caller has already built them together. A nil Pillars attaches nothing.
It is applied in order with the individual options, so a caller can hand over its pillars and then override one of them:
cachecfg.NewCache[Session](ctx, cfg, cachecfg.WithPillars(pillars), cachecfg.WithMetricsProvider(nil), // this cache stays unmetered )
func WithTracerProvider ¶
WithTracerProvider attaches a tracer provider, enabling spans on every cache operation. An absent tracer provider traces nowhere.