A2UI.Plug.ConnectionRegistry (A2UI v0.3.0)

Copy Markdown View Source

ETS-based registry mapping SSE connection IDs to handler pids.

Used by A2UI.Plug.SSE and A2UI.Plug.JSONRPC to route JSON-RPC requests to the correct SSE handler process. Monitors registered pids and auto-cleans entries when a handler exits.

Add to your application's supervision tree:

children = [
  A2UI.Plug.ConnectionRegistry,
  # ...
]

Lazy usage (development / testing)

A2UI.Plug calls ensure_started/0 automatically on first request. The registry runs unsupervised in this mode — acceptable for development but not recommended for production.

Design note: why ensure_started is in call/2, not init/1

Phoenix calls Plug.init/1 at compile time during router macro expansion. Spawning a GenServer there either fails (application not started) or creates an orphan process that is destroyed when the compiler finishes. ensure_started/1 is called from call/2 instead — the happy path is a single :ets.whereis NIF call (~ns). In production the supervision tree starts the registry before any request arrives, making the call/2 check a no-op.

Summary

Functions

Returns a specification to start this module under a supervisor.

Ensures the registry is running. Starts an unlinked process if not already started. Safe to call multiple times — the happy path is a single :ets.whereis check.

Looks up the handler pid for a connection ID.

Registers a connection ID to a handler pid.

Starts the registry as a linked process (for supervision trees).

Removes a connection from the registry.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

ensure_started(table \\ A2UI.Plug.ConnectionRegistry)

@spec ensure_started(atom()) :: :ok

Ensures the registry is running. Starts an unlinked process if not already started. Safe to call multiple times — the happy path is a single :ets.whereis check.

lookup(conn_id, table \\ A2UI.Plug.ConnectionRegistry)

@spec lookup(String.t(), atom()) :: {:ok, pid()} | {:error, :not_found}

Looks up the handler pid for a connection ID.

register(conn_id, pid, table \\ A2UI.Plug.ConnectionRegistry)

@spec register(String.t(), pid(), atom()) :: :ok

Registers a connection ID to a handler pid.

The registry monitors the pid and auto-removes the entry if the handler process exits without calling unregister/2.

start_link(opts \\ [])

@spec start_link(keyword()) :: GenServer.on_start()

Starts the registry as a linked process (for supervision trees).

unregister(conn_id, table \\ A2UI.Plug.ConnectionRegistry)

@spec unregister(String.t(), atom()) :: :ok

Removes a connection from the registry.