Elyra
Elyra The coding agent e The native code editor Elyra Grove Native local development environment Askr The real server for Laravel & PHP Elyra Framework Rust + Svelte 5 framework for desktop apps Elyra Conductor Local project conductor Elyra SQL Server MySQL-compatible SQL server in Rust Elyra Félagi Agents as teammates on one board Elyra SQL Client Native desktop SQL workbench Elyra SQL Anywhere Replication-ready SQL engine Elyra Sjá SEO & GEO workspace for macOS Elyra DataGrid Server-driven data grid for Laravel
Release notes
Changelog
Elyra

Cache

An ergonomic key-value cache facade — the desktop-side counterpart to Askr's shared cache, with the same surface as Laravel's Cache::. One ecosystem: an app reaches for Cache::remember(...) in both worlds; here it's an in-process, TTL-aware store (not a shared-memory region — a desktop app is a single process).

Add the provider to enable it:

use elyra::App;
use elyra::cache::CacheProvider;

App::new().provider(CacheProvider).run()?;

Rust API

Resolve it from the container:

use elyra::cache::Cache;
use std::time::Duration;

#[command]
async fn dashboard(ctx: Ctx) -> Stats {
    let cache = ctx.get::<Cache>();

    // Compute once, reuse for 60s.
    cache.remember("stats", Some(Duration::from_secs(60)), || compute_stats())
}

Full surface:

cache.put("key", "value", Some(Duration::from_secs(300)));  // TTL; None = forever
cache.get("key");                                           // Option<serde_json::Value>
cache.add("once", true, None);                              // set-if-absent (atomic) -> bool
cache.has("key");
cache.forget("key");
cache.increment("hits", 1);                                 // atomic counter -> i64
cache.decrement("hits", 1);
cache.flush();

// Typed helpers (serde):
cache.put_as("user", &user, None);
let user = cache.get_as::<User>("user");

Frontend API (@elyra/runtime)

The same cache instance, from Svelte:

import { cache } from "@elyra/runtime";

await cache.put("theme", "dark", 3600);      // expires in 1h
const theme = await cache.get<string>("theme");
const n = await cache.increment("clicks");
await cache.forget("theme");

Cache vs Store vs Database

Use Reach for
Ephemeral, TTL'd values, counters, memoization Cache (this)
Durable app settings (survive restarts) Store
Structured, queryable data database

The cache lives in memory and is cleared when the app exits.

Limits and eviction

The cache is bounded — a frontend that keeps calling cache.put can't grow it until the process dies:

App::new().provider(CacheProvider::with_limits(5_000, 32 * 1024 * 1024))

Defaults: 10 000 entries / 64 MiB (DEFAULT_MAX_ENTRIES, DEFAULT_MAX_BYTES). When a cap is hit, expired entries go first, then the least recently used. bytes_used() and len() report the current usage; a background sweeper prunes expired entries every 60s so keys nobody reads again don't linger.

TTLs and sleep

A deadline is tracked on both the monotonic and the wall clock, and an entry expires when either has passed. Instant alone doesn't advance while the machine sleeps (a 5-minute TTL survived an overnight suspend); the wall clock alone can jump backwards.

Atomic counters

// One lock for the whole check-and-increment (what RateLimiter uses).
if let Some(n) = cache.increment_if_below("login:ada", 5, Some(Duration::from_secs(60))) {
    // attempt n of 5
}

Related