Mob.Diag.Subscribers (mob v0.9.7)

Copy Markdown View Source

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.

Summary

Functions

Returns a specification to start this module under a supervisor.

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

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

list(topic)

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