Raxol. AgentClientProtocol. Session. Supervisor
(Raxol Agent Client Protocol v0.1.0)
Copy Markdown
View Source
The per-connection DynamicSupervisor for Raxol.AgentClientProtocol.Session
processes.
This is child #2 of the ConnectionSupervisor subtree
(:one_for_all, auto_shutdown: :any_significant); its siblings are the
per-connection Task.Supervisor (#1) and the Connection (#3, significant).
It is restart: :permanent, and its children — Sessions — are :temporary:
- A session crash is NOT auto-restarted. A blank respawned session would lie to
the client (accept prompts against state the client believes exists). Instead
the crash surfaces as an error on the in-flight request (adopter-death →
-32603at the Connection) and the client re-establishes viasession/load— journal replay is the ONLY resurrection path. - Restart intensity is therefore irrelevant (temporary children never count), so a hot-crashing handler can't take the subtree down with it.
Cleanup is entirely monitor-based: a dead Session's SessionRegistry key is
pruned by the Registry's own owner-monitor — there is no hand-rolled sessions
map anywhere. The Session registers itself via its :via name inside
Session.start_link/1, so start_session/2 need only pass the child spec; the
register-before-respond ordering is a start_link/init property, not
something this module arranges.
Package Registry and Task.Supervisor wiring
The SessionRegistry is a single package-level, name-registered Registry with
:unique keys {conn_pid, session_id}. Registry names must be atoms, so
a per-connection registry would need dynamic atoms — the atom-DoS this package
bans; hence ONE shared Registry, keyed by the (stable-for-the-subtree-lifetime)
Connection pid. It is normally started by the library Application; the helpers
here (registry_child_spec/0, child_specs/1) exist so a host tree — or a test
— can assemble the pieces without reaching across module boundaries.
Summary
Functions
Returns a specification to start this module under a supervisor.
The two per-connection infrastructure children that must start BEFORE the
Connection: the Task.Supervisor and this
Session.Supervisor. A host ConnectionSupervisor prepends these to its child
list (Connection last, significant: true); the returned :ids let the
Connection resolve the sibling pids in handle_continue/2.
Child spec for the package-level SessionRegistry (unique keys). A host tree's
Application starts exactly this once; the Connection reads the same Registry
for session/cancel direct dispatch, so the key shape is contract.
Start the per-connection Session DynamicSupervisor. Pass :name to register
it (a host tree keys one per connection; tests may start it anonymously);
:max_sessions caps concurrent live Sessions (default 1000).
Start a Session under this supervisor as a :temporary child. The Session
registers itself on {conn, session_id} via its :via name, so a duplicate live
id returns {:error, {:already_started, pid}} — the caller (the session/new /
session/load handler) maps that to invalid-params.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec child_specs( task_sup_name: term(), session_sup_name: term(), max_inbound_tasks: pos_integer(), max_sessions: pos_integer() ) :: [Supervisor.child_spec()]
The two per-connection infrastructure children that must start BEFORE the
Connection: the Task.Supervisor and this
Session.Supervisor. A host ConnectionSupervisor prepends these to its child
list (Connection last, significant: true); the returned :ids let the
Connection resolve the sibling pids in handle_continue/2.
@spec registry_child_spec() :: Supervisor.child_spec()
Child spec for the package-level SessionRegistry (unique keys). A host tree's
Application starts exactly this once; the Connection reads the same Registry
for session/cancel direct dispatch, so the key shape is contract.
@spec start_link(keyword()) :: Supervisor.on_start()
Start the per-connection Session DynamicSupervisor. Pass :name to register
it (a host tree keys one per connection; tests may start it anonymously);
:max_sessions caps concurrent live Sessions (default 1000).
@spec start_session(Supervisor.supervisor(), keyword()) :: DynamicSupervisor.on_start_child()
Start a Session under this supervisor as a :temporary child. The Session
registers itself on {conn, session_id} via its :via name, so a duplicate live
id returns {:error, {:already_started, pid}} — the caller (the session/new /
session/load handler) maps that to invalid-params.
session_opts is the Session.start_link/1 keyword list (:session_id,
:conn, :mode_state, :task_sup, :turn_runner, :config, :conn_mod).