Skip to content

In-Memory Cache

pkg/cache/memory provides in-process caches backed by otter v2 (adaptive W-TinyLFU). It registers a *cache.Registry in DI; application modules pull typed caches out of it by name.

Declare caches by name up front — either in config or in code with WithCache. Each cache is sized by a memory.Spec (max entry count, TTLs, stats).

lakta.NewRuntime(
config.NewModule(
config.WithConfigDirs(".", "./config"),
config.WithArgs(os.Args[1:]),
),
tint.NewModule(),
slog.NewModule(),
otel.NewModule(),
memory.NewModule(
memory.WithCache("users", memory.Spec{
MaxSize: 10_000,
TTL: 5 * time.Minute,
RecordStats: true,
}),
),
)

Resolve the *cache.Registry from DI, then bind concrete key/value types with cache.Named. The first call for a name fixes its (K, V) and builds the underlying cache; later calls with the same name return the same handle.

reg, err := lakta.Invoke[*cache.Registry](ctx)
if err != nil {
return err
}
users, err := cache.Named[string, *User](reg, "users")
if err != nil {
return err
}
users.Set("u1", &User{Name: "Ada"})
u, ok := users.Get("u1")

GetOrLoad is dogpile-safe: for a given key the loader runs exactly once across concurrent callers.

u, err := users.GetOrLoad(ctx, "u1", func(ctx context.Context, id string) (*User, error) {
return fetchUser(ctx, id)
})

cache.Memoize wraps a cache and loader into a plain lookup function. reg.Stats() returns per-cache hit/miss/eviction/size counters, and caches with RecordStats: true also export otel metrics.

Changing a cache’s max_size in config resizes the live cache with no entry loss. Changing ttl, ttl_access, or record_stats rebuilds the cache and drops all entries (a warning is logged). Adding or removing a cache name registers or tears down that cache.

memory.NewModule(
memory.WithName("sessions"),
memory.WithCache("tokens", memory.Spec{MaxSize: 50_000, TTLAccess: 30 * time.Minute}),
),

Prefer snake_case cache names — names with hyphens cannot be overridden via environment variables.

Config path: modules.cache.memory.<name>

cachescaches holds config-declared caches. Prefer snake_case names; hyphens
caches.max_sizeint

entry-count bound -> otter MaximumSize

env
caches.ttltime.Duration

expire-after-write; 0 = none

env
caches.ttl_accesstime.Duration

expire-after-access; 0 = none

env
caches.record_statsbool

attach the otel StatsRecorder

env

These options can only be set in Go code via With*() functions, not via config files or environment variables.

OptionTypeDescription
WithCache(...)map[string]memory.Specregisters a cache in code (code-only); config with the same name