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 → -32603 at the Connection) and the client re-establishes via session/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

child_spec(arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

child_specs(opts \\ [])

@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.

registry_child_spec()

@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.

start_link(opts \\ [])

@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).

start_session(supervisor, session_opts)

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).