crates.io ↗

iet-cache

core contract official

Defines one typed cache contract; storage, eviction, and serialization belong to implementations.

CoreFeaturesIntegrationsStacksTooling
Used byiet-auth-session-cacheiet-cache-memoryiet-rate-limit
iet-cachecontractCache contract
Depends oniet-corecontract

How to use it

iet-cache defines typed cache contracts: Cache (with get, put, invalidate, prefix invalidation, atomic window counters, and get_or_load), plus CacheKey::scoped for collision-free keys. Storage, serialization, and scope live in adapters such as iet-cache-memory; this crate only fixes the shape.

rust
// examples/htmx-starter/crates/task-impl-timescale/src/service.rs
use iet_cache::{Cache, CacheKey};
use iet_core::TransactionSession;

// `page: u32` is the request parameter; include scope, operation, and query args.
let page_key = page.to_string();
let key = CacheKey::scoped(
    "tasks.v1",
    "list",
    &[&actor.subject, query, &page_key, &revision],
);
let mut session = self.database.session();
let transaction_active = session.state() != iet_core::TransactionState::Idle;
let result = self
    .cache
    .get_or_load(&key, self.ttl, transaction_active, || async {
        // Read-through: only runs on a miss, and never while a transaction is active.
        self.repository.list(&actor.subject, query, page, &mut scope).await
    })
    .await?;
  • A zero TTL removes the key; a backend error is never reported as a cache miss.
  • invalidate_prefix callers must not treat success as done until matching keys are unreadable.

How it works

get_or_load consults Cache::get first; on a miss it runs the loader once and stores the value with Cache::put, so concurrent readers of the same CacheKey do not each hit the backend.

sequenceDiagram
  participant C as "Caller"
  participant H as "Cache"
  participant L as "loader closure"
  C->>H: "get_or_load key ttl transaction_active"
  alt hit
    H-->>C: "cached value"
  else miss
    H->>L: "load"
    L-->>H: "value"
    H->>H: "put key value ttl"
    H-->>C: "value"
  end

Core contract

This page is the crate reference. For the framework-wide runtime and trait model, read Architecture.

What it implements

  • Defines the traits other crates implement: Cache.

What's inside

Modules

  • src/lib.rs

Public API

(root)

  • struct CacheKey
  • struct CounterWindow
  • pub fn scoped(namespace: &str, operation: &str, parts: &[&str]) -> Self — Include visibility scope, operation and all query arguments. Never credentials.
  • trait Cache — One concrete value type per cache capability. No serialization requirement. Errors are not misses. Zero TTL removes the key. Read-through calls bypass storage during transactions. Implementations must make prefix invalidation complete before returning success.
rust
pub trait Cache: Send + Sync {
    type Value: Clone + Send + Sync;
    /// Atomically create at one or saturating-increment, preserving live expiry.
    /// Reject zero windows. Never evict live counters or use separate get/put.
    fn increment_window(
        &self,
        key: &CacheKey,
        window: Duration,
    ) -> impl Future<Output = AppResult<CounterWindow>> + Send
    where
        Self::Value: From<u64> + Into<u64>;
    fn get(&self, key: &CacheKey) -> impl Future<Output = AppResult<Option<Self::Value>>> + Send;
    fn put(
        &self,
        key: &CacheKey,
        value: Self::Value,
        ttl: Duration,
    ) -> impl Future<Output = AppResult<()>> + Send;
    fn invalidate(&self, key: &CacheKey) -> impl Future<Output = AppResult<()>> + Send;
    /// Invalidate keys whose scoped components begin with `prefix`.
    /// Backends must not report success while a matching entry remains readable.
    fn invalidate_prefix(&self, prefix: &CacheKey) -> impl Future<Output = AppResult<()>> + Send;
    fn get_or_load<F, L>(
        &self,
        key: &CacheKey,
        ttl: Duration,
        transaction_active: bool,
        load: L,
    ) -> impl Future<Output = AppResult<Self::Value>> + Send
    where
        F: Future<Output = AppResult<Self::Value>> + Send,
        L: FnOnce() -> F + Send;
}

Depends on

Used by

In this repository

  • examples/htmx-starter

Source: crates/core/iet-cache