crates.io ↗

iet-cache-memory

feature implementation official

Bounded, typed, process-local cache; clones share the same store.

CoreFeaturesIntegrationsStacksTooling
Used byno framework crate yetexamples/handbook-notesexamples/htmx-starter
iet-cache-memoryimplementationIn-memory cache
Depends oniet-telemetrycontractiet-corecontractiet-cachecontract

How to use it

iet-cache-memory is the bounded, typed in-process cache: one concrete value type T per cache, with no serialization or trait objects. Clones share the same store, and it implements the iet-cache Cache trait (get/put/get_or_load/prefix invalidation plus atomic counter windows) used by iet-rate-limit and session caches.

rust
// crates/features/iet-cache-memory/src/lib.rs (tests)
use iet_cache::{Cache, CacheKey};
use iet_cache_memory::MemoryCache;
use std::time::Duration;

let cache = MemoryCache::new(1024)?;          // capacity bounds live entries
let peer = cache.clone();                     // clones share one store
let key = CacheKey::scoped("tenant-a", "user", &["42"]);
let ttl = Duration::from_secs(30);

cache.put(&key, profile, ttl).await?;
let loaded = peer
    .get_or_load(&key, ttl, false, || async {
        // Runs only on a miss; a cached value skips this loader.
        load_profile().await
    })
    .await?;
peer.invalidate_prefix(&CacheKey::scoped("tenant-a", "user", &[])).await?;
  • New keys fail with Unavailable once capacity is reached; live entries are never evicted, and expired ones are reclaimed first. A zero TTL removes the key.
  • get_or_load(..., transaction_active, ...) bypasses the cache during a transaction; errors propagate and are never cached as values.
  • MemoryCache::<u64> also powers fixed-window counters via increment_window, which is how iet-rate-limit counts requests.

How it works

Each cache is a Mutex-guarded HashMap shared through an Arc, so clones see one store and the capacity bounds live entries rather than heap bytes. get_or_load first calls get; a hit returns immediately, a miss runs the caller's loader and stores the result with put, and put reclaims expired entries before enforcing capacity. Counting and invalidation are separate trait operations on the same store.

flowchart LR
  A["get_or_load"] --> B["get"]
  B -->|hit| C["return cached value"]
  B -->|miss| D["load closure"]
  D --> E["put"]
  E --> F{"capacity reached"}
  F -->|yes| G["Unavailable error"]
  F -->|no| H["store entry with TTL"]
  I["increment_window"] --> J["atomic counter"]
  K["invalidate_prefix"] --> L["retain non-matching keys"]

What it implements

  • Implements iet_cache::Cache from iet-cache.

What's inside

Modules

  • src/lib.rs

Public API

(root)

  • struct CacheStats
  • struct HotKey
  • struct MemoryCache — Clones share the same cache. Capacity bounds entry count, not heap bytes in T. New keys fail at capacity; live entries are never evicted.
  • pub fn new(capacity: usize) -> AppResult<Self>
  • pub fn analytics(mut self, name: &'static str, family: &'static str) -> Self — Static cache/key-family vocabulary, never a raw key or customer identifier.
  • pub fn hot_key_analytics(mut self, capacity: usize) -> AppResult<Self> — Opt-in approximate heavy hitters. Random keyed hashes are process-local; raw keys are never retained/exported. Disabled by default, including Debug.
  • pub fn hot_key_snapshot(&self) -> Vec<HotKey>
  • pub fn stats(&self) -> AppResult<CacheStats>

Impl map

  • Clone for MemoryCache<T>
  • Cache for MemoryCache<T>

Depends on

Used by

  • No other framework crate depends on it directly.

In this repository

  • examples/handbook-notes
  • examples/htmx-starter

Source: crates/features/iet-cache-memory