Durable single-node session host for req_managed_agents.
Turns RMA's per-call ReqManagedAgents.Session into a supervised, crash-survivable,
idle-detachable hosted session keyed by a caller-supplied external id. One public
function — ReqManagedAgents.Host.send_message/3 — finds, starts, or reattaches the
right session, runs it to a terminal, and returns the RMA SessionResult, with the
session's upstream identity durably persisted so a BEAM restart resumes the conversation.
Installation
def deps do
[
{:req_managed_agents_host, "~> 0.1.0"}
]
endQuickstart
Every call needs a :provider (a ReqManagedAgents.Provider), a :handler (a
ReqManagedAgents.Handler), and a :store — a {module, opts} pair naming a
ReqManagedAgents.Host.Store implementation.
In-memory (ETS)
Fastest option; the locator is gone if the owning process stops. Good for a single long-lived node where losing in-flight session pointers on a crash is acceptable.
{:ok, _pid} = ReqManagedAgents.Host.Store.ETS.start_link(name: :sessions)
store = {ReqManagedAgents.Host.Store.ETS, name: :sessions}
opts = [provider: MyProvider, handler: MyHandler, store: store]
{:ok, %ReqManagedAgents.SessionResult{text: text}} =
ReqManagedAgents.Host.send_message("customer-42", "hello", opts)
# same external id later — even after the SessionServer idle-detached or crashed —
# reattaches the same upstream session instead of minting a new one
{:ok, _result} = ReqManagedAgents.Host.send_message("customer-42", "what's next?", opts)File-backed (DETS)
Use this when the locator itself must survive a full BEAM restart, not just a process crash — e.g. a deploy or a node bounce. The upstream session id is written to disk on every turn, so re-opening the same file after a restart reattaches exactly where the conversation left off.
{:ok, _pid} =
ReqManagedAgents.Host.Store.DETS.start_link(name: :sessions, file: "/var/data/sessions.dets")
store = {ReqManagedAgents.Host.Store.DETS, name: :sessions, file: "/var/data/sessions.dets"}
opts = [provider: MyProvider, handler: MyHandler, store: store]
{:ok, _result} = ReqManagedAgents.Host.send_message("customer-42", "hello", opts)
# ...BEAM restarts; the same store is reopened from the same file on boot...
{:ok, _result} = ReqManagedAgents.Host.send_message("customer-42", "still there?", opts)Idle-detach
Sessions idle-detach after idle_timeout_ms (default 300_000ms / 5 minutes) of inactivity —
the SessionServer stops, but the Locator row (and thus the upstream session id) survives,
so the next send_message/3 for the same external id starts a fresh server and reattaches:
opts = [provider: MyProvider, handler: MyHandler, store: store, idle_timeout_ms: 60_000]Durability model
- Live handle vs. durable state. A
SessionServeris a reattachable live handle, not the durable record — theLocator(backed by your chosenStore) is. The server's child spec isrestart: :temporary: an idle-detach or a crash both simply end the process, and neither is auto-restarted by theSessionSupervisor— the nextsend_message/3starts a fresh one and reattaches through theLocator. - Crash isolation. Each external id's session runs under its own
DynamicSupervisorchild; one session crashing never affects another. Store.ETSvs.Store.DETS. PickETSfor process-crash isolation only; pickDETSwhen the locator must also survive a BEAM/node restart.
License
Apache-2.0. See LICENSE.