Runtime
Sessions and resume
A session is a bounded attachment between a user id, an owner pid, and the instance’s ETS indexes. The owner is the process that receives {:"$wiregrid", envelope}. Cowboy, the foreign gateway, and Wiregrid.Consumer.Worker are owners. An ordinary Elixir process can be one too.
Starting an instance
{:ok, _pid} = Wiregrid.start_instance(:chat, profile: :small)
# or, inside a supervision tree:
Wiregrid.instance_child_spec(:chat, profile: :balanced)
start_instance/2 builds config, then starts a permanent child under Wiregrid.InstanceSupervisor. Starting an instance that is already up returns {:ok, pid} for the existing supervisor. stop_instance/1 returns {:error, :not_found} when the name is absent. Unknown or duplicate options fail in Wiregrid.Config.build/1 before any table is created.
Connect
{:ok, session_id} = Wiregrid.connect(:chat, "alice", self())
{:ok, session_id} = Wiregrid.connect(:chat, "alice", self(),
metadata: %{"role" => "member"},
status: :online,
ack_mode: :manual,
delivery_format: :term
)
Accepted connect options are :metadata, :status, :presence_metadata, :ack_mode, and :delivery_format.
| Option | Default | Values |
|---|---|---|
ack_mode | :manual | :manual or :transport |
delivery_format | :term | :term, :encoded, :both |
:term puts the decoded event on the envelope under :event. :encoded puts the codec bytes under :payload and leaves decoding to the consumer. :both includes both keys. Gleam’s connect_encoded asks for delivery_format: :encoded.
Session ids are binaries, at most max_session_id_bytes (96 on the base config). User ids are bounded by max_user_id_bytes (512). Metadata is bounded by max_metadata_bytes (16,384).
Two caps apply at once. max_sessions_per_user is 32 on the base config and is not replaced by the profile. max_sessions_per_owner limits how many sessions share one pid: 32 on :small, 128 on :balanced, and 1,024 on :large. The base map also lists 128, and the selected profile overwrites it.
Resume tokens
{:ok, session_id, token} = Wiregrid.connect_resumable(:chat, "alice", self())
{:ok, %{session_id: new_id, resume_token: next, restored: restored}} =
Wiregrid.resume_session(:chat, "alice", self(), token)
The token is random, stored as a hash, bound to the same user, and single use. A successful resume rotates it. resume_ttl_ms defaults to 120,000. reconnect_grace_ms defaults to 15,000 and covers the window in which room membership can be held after the old owner exits.
restored reports subscriptions, presence watches, and rooms separately. Each domain has its own success and failure counts. Restored edges are authorized again. A resume does not keep a permission the authorizer would now refuse.
Wiregrid.resume_room(instance, room, old_session_id, new_session_id) moves one room edge when the caller already holds both session ids.
Actors
{:ok, actor} = Wiregrid.connect_actor(:chat, "alice", self())
{:ok, actor, token} = Wiregrid.connect_resumable_actor(:chat, "alice", self())
{:ok, actor, next, restored} = Wiregrid.resume_actor(:chat, "alice", self(), token)
{:ok, actor} = Wiregrid.actor(:chat, session_id)
Wiregrid.Actor is a struct with instance, session_id, and user_id. Its functions pass that session id into publish, subscribe, presence, rooms, ack, and rate-limit calls. It does not cache an authorization decision. Wiregrid.Actor.rate_limit/5 folds the session id into the limiter key.
Changing and closing a session
:ok = Wiregrid.set_session_metadata(:chat, session_id, %{"desk" => "eu"})
:ok = Wiregrid.disconnect(:chat, session_id, :normal)
:ok = Wiregrid.disconnect_user(:chat, "alice", :replaced)
disconnect/3 and disconnect_user/3 default the reason to :normal. Disconnect releases delivery reservations for that session. session/2, user_sessions/3, subscriptions/3, and session_state/3 return bounded summaries. They do not return owner pids, monitor refs, resume-token hashes, or ETS table identifiers.
Reconciling topology
:ok = Wiregrid.sync_subscriptions(:chat, session_id, [{:channel, "general"}, {:channel, "ops"}])
{:ok, report} = Wiregrid.sync_topology(:chat, session_id, %{
subscriptions: [{:channel, "general"}],
presence_watches: ["bob"],
rooms: ["lobby"]
})
sync_subscriptions/4 makes the subscription set match the list. sync_topology/4 accepts a map with :subscriptions, :presence_watches, and :rooms. Omitted domains are left alone. Each requested domain reports on its own. Wiregrid does not present several edge sets as one distributed transaction.
subscribe_many/4, unsubscribe_many/3, join_rooms/4, leave_rooms/3, watch_presence_many/4, and sync_presence_watches/4 are the bounded batch forms. List lengths are checked against the relevant per-session caps before the runtime applies them.