# `Mob.Diag.Subscribers`
[🔗](https://github.com/genericjam/mob/blob/master/lib/mob/diag/subscribers.ex#L1)

Who is listening to a diagnostic stream: `Mob.Defect.Bus` (`:defect_bus`) and
`Mob.Event.Trace` (`:event_trace`).

The write paths read the list from `:persistent_term` and `send/2` to each pid,
with no process on the hot path. This process only changes the list, and
monitors every subscriber so one that exits is pruned.

A subscriber on another node whose connection drops (`:noconnection`) is
*parked*, not pruned: it leaves the published list, so no emit sends to it
(a `send/2` to an unconnected node dials it, which over `adb` cannot
succeed), but its topics and meta are kept. When its node reconnects it is
monitored again and republished, so a host shell that re-dials the device
keeps receiving without re-subscribing; if the pid died meanwhile, the new
monitor prunes it. A parked subscriber whose node stays away for
`config :mob, :subscriber_park_ms` (default 10 minutes) is dropped.

It is separate from the stores' table owners on purpose. An owner that also
did subscriber bookkeeping could lose every recorded defect to a bug in that
bookkeeping. And if this process dies, the published lists and the parked
subscribers survive in `:persistent_term`, so delivery continues, and the
next instance re-monitors every pid it finds there.

A subscriber is any pid, including one on a connected node:
`:rpc.call(node, Mob.Defect.Bus, :subscribe, [self()])` subscribes the calling
shell, where passing no pid would subscribe the short-lived process `:rpc`
runs the call in.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `list`

```elixir
@spec list(atom()) :: [{pid(), term()}]
```

The subscribers of `topic` as `{pid, meta}` pairs, read from
`:persistent_term` with no process involved.

The first read in a VM that has never started this registry starts it once,
so subscribers an older `mob` left behind (after a hot push) are adopted
rather than silently dropped. Every later read is a lookup. This never
raises: it sits under every `Mob.Event.dispatch/4`, so if the registry cannot
be started the read answers from what is published.

---

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