portunus_joiner (portunus v0.14.0)
View SourceRuns the cluster join and convergence loop around
portunus:join_or_form/3: one process per cluster, supervised by the
consumer.
While joining, each pass runs the ensure_system fun and then
join_or_form/3, retrying with backoff. Once joined, each pass only
checks membership and rejoins when the check fails:
portunus:is_member/1 catches a dead or reset local server,
portunus:is_seed_cluster_member/2 catches a node the seed's cluster
dropped.
The subscriber (by default the process that called start_link/1)
receives {portunus_joiner, Name, joined} and
{portunus_joiner, Name, rejoining}. These are status reports, not
edges: a restarted joiner reports joined again with no rejoining in
between.
Wait for joined before registering children, and do not stop anything
on rejoining: it is often a false alarm, and leases protect running
children.
Removing departed members stays with the consumer: only the host knows
that a node is gone for good. See portunus:remove_member/2.
Summary
Functions
The decision core: an event and the current state in, the actions and
the next state out. It is pure, so the unit and property suites drive it
without a cluster. The gen_server runs the passes and performs the
actions.
Re-evaluate membership now. Call this from the host's membership event handler. It is asynchronous, and a burst of calls runs one pass.
Start a joiner for cluster name on Ra system system, linked to the
caller.
Types
-type action() :: {notify, joined | rejoining} | {arm, non_neg_integer()}.
-type decide_state() :: #{status := status(), backoff_ms := pos_integer(), recheck_interval_ms := pos_integer()}.
-type event() :: trigger | pass_ok | {pass_failed, term()}.
-type opts() :: #{system := portunus:system(), name := portunus:name(), candidates := fun(() -> [node()]), ensure_system => fun(() -> portunus:ok_or_error(term())), subscriber => pid(), recheck_interval_ms => pos_integer()}.
-type status() :: joining | member.
Functions
-spec decide(event(), decide_state()) -> {[action()], decide_state()}.
The decision core: an event and the current state in, the actions and
the next state out. It is pure, so the unit and property suites drive it
without a cluster. The gen_server runs the passes and performs the
actions.
A trigger re-arms the single timer to fire immediately, so bursts
coalesce into one pass. A failed pass while joining doubles the backoff.
A failed membership check reports rejoining and rejoins on the next,
immediately armed pass.
-spec recheck(pid()) -> ok.
Re-evaluate membership now. Call this from the host's membership event handler. It is asynchronous, and a burst of calls runs one pass.
Start a joiner for cluster name on Ra system system, linked to the
caller.
candidates returns the nodes that should form one cluster, typically
the host's membership view. node() is added and the list sorted. A
raising fun counts as a failed attempt and is retried.
ensure_system runs before every join attempt and defaults to a fun
returning ok. A tenant of a host-owned system passes
fun() -> portunus:use_system(System) end. The fun is retried with the
join because it can fail early in the host's boot.
recheck_interval_ms (default 60000) paces the periodic membership
re-check.