arizona_pubsub (arizona v0.4.0)
View SourceThin wrapper over pg for channel-based pub/sub.
Subscribers join a channel (any term) by pid and receive whatever is
broadcast to that channel as a plain mailbox message. There's no
serialization or queueing -- it's just pg:join/3 plus a fan-out send.
The broadcast paths iterate pg's raw membership list without sorting or
deduplicating -- a per-message usort over the whole member list would tax
every broadcast (and every subscribe) to paper over a state only two
concurrent subscribes of the SAME pid can create (subscribe/2's
check-then-join is not atomic). In that essentially-unreachable state a
subscriber receives one copy per membership until unsubscribe/2 clears
them all; subscribers/1 still reports each pid once.
Used by arizona_reloader_rule (file change events), arizona_reloader
(dev hot reload), and any handler that wants cross-process messaging
(e.g. multi-tab chat in arizona_chat).
Example
1> arizona_pubsub:start_link().
2> arizona_pubsub:subscribe(my_topic, self()).
ok
3> arizona_pubsub:broadcast(my_topic, {hello, world}).
ok
4> receive Msg -> Msg end.
{hello, world}
Summary
Functions
Sends Data as a mailbox message to every subscriber of Channel
(one copy per pg membership -- see the moduledoc).
Like broadcast/2 but skips From -- useful when the publisher is
also a subscriber and shouldn't echo to itself.
Subscribes the caller to membership changes on Channel. It begins receiving
{Ref, join, Channel, Pids} and {Ref, leave, Channel, Pids} messages as pids
join or leave -- a leave fires on a subscriber's process death too -- and returns
the monitor reference plus the current members. The monitor is removed
automatically when the caller exits.
Starts the pubsub pg scope. Called from the application supervisor.
Subscribes Pid to Channel. Returns {error, already_joined} if
the pid is already subscribed.
Returns the pids currently subscribed to Channel, each once.
Unsubscribes Pid from Channel. Returns {error, not_joined} if
the pid was not a subscriber.
Types
-nominal channel() :: term().
Functions
Sends Data as a mailbox message to every subscriber of Channel
(one copy per pg membership -- see the moduledoc).
-spec broadcast_from(From, Channel, Data) -> ok when From :: pid(), Channel :: channel(), Data :: term().
Like broadcast/2 but skips From -- useful when the publisher is
also a subscriber and shouldn't echo to itself.
Subscribes the caller to membership changes on Channel. It begins receiving
{Ref, join, Channel, Pids} and {Ref, leave, Channel, Pids} messages as pids
join or leave -- a leave fires on a subscriber's process death too -- and returns
the monitor reference plus the current members. The monitor is removed
automatically when the caller exits.
Useful for presence, e.g. a view that shows a live count of connected peers.
-spec start_link() -> gen_server:start_ret().
Starts the pubsub pg scope. Called from the application supervisor.
-spec subscribe(Channel, Pid) -> ok | {error, already_joined} when Channel :: channel(), Pid :: pid().
Subscribes Pid to Channel. Returns {error, already_joined} if
the pid is already subscribed.
The membership check is a read followed by a join, so two concurrent
subscribes of the same pid can both return ok and both reach pg
(which has no atomic join-if-absent). subscribers/1 reports each pid
once regardless, and unsubscribe/2 drops every pg membership the pid
holds rather than leaving a stray one behind; until then a broadcast
delivers one copy per membership (see the moduledoc).
Returns the pids currently subscribed to Channel, each once.
pg memberships are a multiset and subscribe/2's check-then-join is
not atomic, so a pid can hold more than one membership; this diagnostic
view deduplicates. The broadcast paths deliberately do not (see the
moduledoc), so they never pay this sort.
-spec unsubscribe(Channel, Pid) -> ok | {error, not_joined} when Channel :: channel(), Pid :: pid().
Unsubscribes Pid from Channel. Returns {error, not_joined} if
the pid was not a subscriber.