A reference ETS adapter for the optional completed-response cache.
Bounded and TTL-aware. :ets has no native TTL, so each entry carries an expiry
monotonic-time deadline and get/1 rejects expired entries (and lazily deletes them). A
max-entries cap bounds steady-state memory; when the cap is reached put/3 evicts the
single oldest-by-deadline entry before inserting, which keeps the hot set resident under
churn without a background sweeper.
The adapter is NOT admission authority — AshOnetime validates every field of a returned
entry against the authoritative PostgreSQL claim before using the payload (see
AshOnetime.Cache). Treat every entry as untrusted.
Supervision
The ETS table is owned by a GenServer started via start_link/1. Add it to your supervision
tree (it owns the table; if it terminates the table is destroyed, which is safe — the cache
is optional and a miss falls through to PostgreSQL):
children = [
# ...your repo...
{AshOnetime.Cache.Ets, max_entries: 10_000}
]Then configure it as the cache module:
config :ash_onetime, cache: AshOnetime.Cache.EtsThe table is named __MODULE__ (one ETS cache per VM). A multi-instance deployment (e.g.
one cache per tenant prefix) wraps this module behind a per-instance module so each gets its
own __MODULE__-named table; the reference adapter is single-instance by design.
Options
:max_entries— the bounded cap;put/3evicts the oldest-by-deadline entry when the cap is reached before inserting (default 10_000). The cap bounds entry COUNT only — the per-entry byte ceiling is enforced upstream byAshOnetime.Cache(max_entry_bytes).
Limitations
This is a reference adapter tuned for simplicity and correctness, not throughput: the
eviction is a single oldest-by-deadline scan, and expired entries are reaped lazily on
get/1 rather than by a background sweeper. A high-throughput deployment should reach for
Redis or a dedicated cache with sampled-LRU eviction and active expiry; this adapter exists
so the cache-degradation path in AshOnetime.Cache is reachable without a third-party
dependency.
Summary
Functions
A supervisor child specification for the owning GenServer.
Drops every entry from the cache (the table and config are retained).
Returns the configured max-entries cap.
Starts the owning GenServer for the ETS table.
Functions
@spec child_spec(keyword()) :: Supervisor.child_spec()
A supervisor child specification for the owning GenServer.
Options
:max_entries— the bounded entry cap (default 10_000).
Add it to your supervision tree:
children = [
{AshOnetime.Cache.Ets, max_entries: 10_000}
]
@spec clear() :: :ok
Drops every entry from the cache (the table and config are retained).
Safe to call while the cache is serving; get/1 calls during a wipe may race with the
delete and return :miss, which is always safe (a miss falls through to PostgreSQL).
@spec max_entries() :: non_neg_integer()
Returns the configured max-entries cap.
@spec start_link(keyword()) :: GenServer.on_start()
Starts the owning GenServer for the ETS table.
Options
:max_entries— the bounded entry cap (default 10_000).
Returns {:ok, pid} or {:error, {:already_started, pid}}.