# `T3.RPC.Reader`
[🔗](https://github.com/dl-alexandre/t3-elixir/blob/main/lib/t3/rpc/reader.ex#L1)

Supervised owner of reconnecting, read-only RPC subscriptions.

Add this child to your application's supervisor. `:connect` is a zero-arity
function returning `{:ok, rpc_options}` and is called on every connection
attempt, so tickets can be freshly minted and local credentials renewed.
`:streams` contains maps with `:key`, `:method`, optional `:payload`, and optional
`:catch_up` (`{method, payload}`). Only explicitly configured catch-up reads are
repeated; arbitrary RPC commands are never replayed.

`:on_event` is a synchronous function receiving `{:snapshot, key, value}`,
`{:chunk, key, values}`, or `{:status, status}`. It must return `:ok` after the
data is consumed; only then is the chunk acknowledged. A callback failure stops
this child so its supervisor can restart it. Do not block indefinitely or send
unbounded messages to a slower consumer from this callback.

Catch-up reads run before subscriptions on each connection. Without a resume
cursor, T3's shell/thread streams start with an authoritative snapshot,
covering changes between the read and subscription. Other protocols need their own cursor/snapshot strategy.
Snapshots/events can repeat across reconnects; reducers must tolerate duplicates.
Opt in to best-effort server replay with `resume: true` on shell/thread stream
maps. Committed sequences are injected as `afterSequence` on reconnect.
`:load_cursor` (`fn key -> integer_or_nil end`) and `:save_cursor`
(`fn key, sequence -> :ok end`) can persist checkpoints across process restarts.
Checkpoints advance after consumption and before ACK; storage/callback failure
stops this child. Replay may coalesce or fall back to a snapshot: this is not
durable audit/billing history. `payload` and catch-up payloads may also be
functions of the last committed sequence, preserving arbitrary supported wire
options without inventing cursor fields on snapshot-only reads.

A chunk callback may return `{:error, :busy}` only when it has consumed none
of that chunk, to defer consumption and withhold its ACK. It is retried every `:consumer_retry_interval` (default 100 ms), keeping
the reader responsive. At most one deferred chunk per configured subscription
is retained; the transport's upstream backpressure bounds further delivery.
This pairs with `T3.RPC.WorkQueue.enqueue/2` for optional asynchronous processing.
Queue admission ACKs before execution and is not durable. Catch-up/status
callbacks must still return `:ok` promptly.

There is no durable delivery guarantee for intermediate events while offline.
Both stream completion and transport failure trigger reconnect. Backoff is
exponential with jitter, bounded by `:min_backoff` (500 ms) and `:max_backoff`
(30 seconds). A successfully consumed chunk resets it. `:jitter` defaults to
0.2 (set zero in deterministic tests).

Set `:health_check` to a read-only `{method, payload}` to detect half-open idle
connections. It runs every `:health_interval` (30 seconds), with a
`:health_timeout` (5 seconds). A failed probe reconnects. Disabled by default.

See the board integration guide for a complete supervision example. Credentials
and callback state are omitted from process status output.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `cursors`

Return committed per-stream sequence cursors (only for resume-enabled streams).

# `start_link`

# `status`

Return `:connected` or `:disconnected` without exposing connection credentials.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
