Skip to content

v0.1.0

Choose a tag to compare

@andared andared released this 05 Sep 22:46
· 32 commits to main since this release

The first release of a small in-memory cache for Go that aims to be predictable before it is fast.

There is no shortage of Go caches, and several of them are excellent. This one exists because the failures that actually cost time in production were never about throughput: a write that reports success and is dropped a moment later, a hit rate that quietly collapses because every value is too big for the budget, a limit expressed in entries when the thing you are protecting is a memory limit, and a batch of keys that all expire in the same millisecond and stampede the upstream together.

import "github.com/andared/sanecache"

Go 1.24 or newer. No dependencies, and that is a hard rule rather than a current state of affairs.

What's in it

  • Cache[K, V] with TTL, optional jitter, and both lazy and background expiry.
  • Byte budgets via MaxBytes and a Cost function, alongside MaxEntries. A byte budget without a cost function is a construction-time panic rather than a budget that silently counts entries.
  • LRU and ClearOnFull eviction policies. The second trades precise eviction for a read path that needs only a read lock.
  • First-class negative caching: SetNegative, SetNegativeTTL, and StatusNegative from Lookup, so "the upstream says this does not exist" does not have to be smuggled inside your value type.
  • Optional sharding via Shards, off by default — the README has the numbers on when it earns its place, and for most services it does not.
  • Built-in counters via Stats, and an OnEvict callback carrying a reason.
  • ErrTooLarge from Set, for values that can never fit and would otherwise fail silently forever.

Stability

The major version is 0: the API may change in any release. Breaking changes are listed in CHANGELOG.md.

Next

A loader with single-flight so a cold key is fetched once rather than once per concurrent caller; typed views over a shared byte budget; and a coarse clock, since half the cost of a lookup today is reading the wall clock to check expiry.

If a different cache fits your problem better, the README says which one and why.