Documentation
¶
Overview ¶
Package echocache provides a generic, concurrency-safe caching layer built on top of pluggable storage backends. It prevents redundant computations under high concurrency by using singleflight deduplication: when multiple goroutines request the same missing key simultaneously, only one refresh function is executed and the result is shared.
Two caching modes are available:
- EchoCache – synchronous: the caller blocks until the value is computed and cached.
- EchoCacheLazy – lazy/stale-while-revalidate: a stale value is returned immediately while a background goroutine silently refreshes the cache entry.
Storage backends live in the github.com/logocomune/echocache/store sub-package and include in-memory LRU, expirable LRU, single-entry, Redis, and NATS JetStream implementations.
Index ¶
Constants ¶
const (
NeverExpire = time.Hour * 24 * 365 * 100
)
NeverExpire represents a duration of 100 years, effectively used to denote a value that should never expire.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type EchoCache ¶
type EchoCache[T any] struct { // contains filtered or unexported fields }
EchoCache is a generic caching mechanism that integrates singleflight to prevent redundant computations. EchoCache uses a Cacher interface for data storage and retrieval, supporting custom refresh functions for cache misses. EchoCache ensures only one computation per key occurs simultaneously to optimize concurrent operations.
func NewEchoCache ¶ added in v1.2.0
NewEchoCache creates a new EchoCache instance to enable caching with optional singleflight for concurrent requests.
func (*EchoCache[T]) FetchWithCache ¶ added in v1.2.0
func (ec *EchoCache[T]) FetchWithCache(ctx context.Context, key string, refreshFn store.RefreshFunc[T]) (T, bool, error)
FetchWithCache retrieves a cached value by key or computes it using a given refresh function, caching the result for future use. Returns the value, a boolean indicating if it was found or computed, and an error if computation or retrieval fails.
type EchoCacheLazy ¶ added in v1.2.0
type EchoCacheLazy[T any] struct { // contains filtered or unexported fields }
EchoCacheLazy is a lazy-refresh cache implementing the stale-while-revalidate pattern. It returns a cached (possibly stale) value immediately and enqueues a background refresh for keys whose value has aged past the configured interval.
Concurrency guarantees:
- singleflight deduplicates concurrent refreshes within the same process.
- TryAcquireRefreshLock / ReleaseRefreshLock (delegated to the backend) prevent thundering-herd across multiple processes / instances.
- A per-key pending-task map (pendingKeys) ensures at most one refresh task is queued per key, protecting the queue from duplicate entries.
- ShutdownLazyRefresh waits for all in-flight background tasks to complete before returning (graceful shutdown via sync.WaitGroup).
func NewLazyEchoCache ¶ added in v1.2.0
func NewLazyEchoCache[T any](cacher store.StaleWhileRevalidateCache[T], refreshTimeout time.Duration, opts ...LazyEchoCacheOption) *EchoCacheLazy[T]
NewLazyEchoCache initialises a lazy echo cache with the given backend and refresh timeout. Background refresh workers are started immediately. Optional LazyEchoCacheOption values can tune queue size and worker count.
func (*EchoCacheLazy[T]) FetchWithLazyRefresh ¶ added in v1.2.0
func (ec *EchoCacheLazy[T]) FetchWithLazyRefresh(ctx context.Context, key string, refreshFn store.RefreshFunc[T], lazyRefreshInterval time.Duration) (T, bool, error)
FetchWithLazyRefresh retrieves a cached value or computes a new value if missing, scheduling a lazy background refresh when the cached value is stale.
If the cached value exists but is older than lazyRefreshInterval, a refresh task is enqueued for background processing (at most one task per key; fix 1.2). If the value is missing or an error occurs, the refreshFn is called synchronously using the caller's context deadline (fix M5).
func (*EchoCacheLazy[T]) ShutdownLazyRefresh ¶ added in v1.2.0
func (ec *EchoCacheLazy[T]) ShutdownLazyRefresh()
ShutdownLazyRefresh gracefully stops the refresh workers:
- Cancels the internal context so workers stop accepting new tasks.
- Closes the task queue (idempotent via sync.Once).
- Waits (fix 2.1) for all in-flight worker goroutines to finish.
It is safe to call ShutdownLazyRefresh multiple times; only the first call triggers the shutdown sequence; subsequent calls are no-ops.
type LazyEchoCacheOption ¶ added in v1.2.1
type LazyEchoCacheOption func(*lazyEchoCacheOptions)
LazyEchoCacheOption is a functional option for NewLazyEchoCache.
func WithQueueSize ¶ added in v1.2.1
func WithQueueSize(n int) LazyEchoCacheOption
WithQueueSize sets the capacity of the background-refresh task queue. The default is 1000. Values ≤ 0 are ignored.
func WithWorkerCount ¶ added in v1.2.1
func WithWorkerCount(n int) LazyEchoCacheOption
WithWorkerCount sets the number of goroutines that drain the background-refresh task queue concurrently. The default is 1. Values ≤ 0 are ignored.