Crema
A Go cache library with probabilistic revalidation and singleflight loading
Install / Use
/learn @abema/CremaREADME
crema ☕️
A Go cache library with probabilistic revalidation and optional singleflight loading. It smooths refreshes near TTL expiry while deduplicating concurrent loads.
Features
- Smooth probabilistic revalidation near expiry
- Built-in singleflight loader (can be disabled)
- Zero external dependencies in the core module
- Pluggable storage (
CacheProvider) and storage codecs (CacheStorageCodec)
Core functionality is covered by a high level of automated tests.
Revalidation Algorithm
Within the revalidation window, the cache reloads with probability
p(t)=1-e^{-kt}
where t is the remaining time. The steepness k is set so that $p(t)=0.999$ at the configured window boundary, smoothing spikes near expiry.
This design is inspired by the following references:
- Cache Stampede: Avoiding Hot Spots in Distributed Caching Systems
- Sometimes I Cache | The Cloudflare Blog
Installation
go get github.com/abema/crema
Go 1.22 or newer is recommended.
Quick Start
provider := newMemoryProvider[int]()
codec := crema.NoopCacheStorageCodec[int]{}
cache := crema.NewCache(provider, codec)
value, err := cache.GetOrLoad(context.Background(), "answer", time.Minute, func(ctx context.Context) (int, error) {
// Database or computation logic here
return 42, nil
})
if err != nil {
panic(err)
}
println(value)
Usage Notes
- CacheProvider: Responsible for persistence with TTL handling. Works with Redis/Memcached, files, or databases.
- CacheStorageCodec: Encodes/decodes cached objects. Swap in JSON, protobuf, or your own codec.
- CacheObject: A thin wrapper holding
Valueand absolute expiry (ExpireAtMillis).
Options
WithRevalidationWindow(duration): Set the revalidation windowWithDirectLoader(): Disable singleflight and call loaders directlyWithMaxLoadTimeout(duration): Set max duration for singleflight loaders (ignored withWithDirectLoader())WithLogger(logger): Override warning logger for get/set failures
Implementations
CacheProvider
| Name | Package | Notes | Example |
| --- | --- | --- | --- |
| RistrettoCacheProvider | github.com/abema/crema/ext/ristretto | dgraph-io/ristretto backend with TTL support. | ✅ |
| RedisCacheProvider | github.com/abema/crema/ext/rueidis | Redis backend using rueidis. | ✅ |
| ValkeyCacheProvider | github.com/abema/crema/ext/valkey-go | Valkey (Redis protocol) backend. | ✅ |
| MemcachedCacheProvider | github.com/abema/crema/ext/gomemcache | Memcached backend with TTL handling. | - |
| CacheProvider | github.com/abema/crema/ext/golang-lru | hashicorp/golang-lru backend with default TTL. | - |
CacheStorageCodec
| Name | Package | Notes | Example |
| --- | --- | --- | --- |
| NoopCacheStorageCodec | github.com/abema/crema | Pass-through codec for in-memory cache objects. | - |
| JSONByteStringCodec | github.com/abema/crema | Standard library JSON encoding to []byte. | ✅ |
| JSONByteStringCodec | github.com/abema/crema/ext/go-json | goccy/go-json encoding to []byte. | - |
| ProtobufCodec | github.com/abema/crema/ext/protobuf | Protobuf encoding to []byte. | ✅ |
| BinaryCompressionCodec | github.com/abema/crema | Wraps another codec and zlib-compresses encoded bytes above a threshold. | ✅ |
MetricsProvider
| Name | Package | Notes | Example |
| --- | --- | --- | --- |
| NoopMetricsProvider | github.com/abema/crema | Embedded base used as the default metrics provider. | - |
Concurrency
Cache is goroutine-safe as long as CacheProvider and CacheStorageCodec implementations are goroutine-safe.
Development
go generate
go test ./...
Tools
cmd/plot-revalidation: SVG plot generator for revalidation curves
Why "crema"?
Crema is the golden foam that forms on top of a freshly pulled espresso coffee shot. Like crema that gradually dissipates over time, this cache library probabilistically refreshes entries, ensuring your data stays fresh without the overhead of deterministic expiration checks.
