portunus_registry (portunus v0.8.0)
View SourceA dynamic cluster-wide supervisor. "Dynamic" isn't an Erlang/OTP supervisor
type here: it means children are added and removed at runtime with add/3
and remove/2, unlike portunus_supervisor, whose children are the fixed
set returned once by init/1.
add/3 registers a child spec (a supervisor:child_spec(), or one carrying
an extended {permanent, Delay} restart option which portunus_delayed_restart
rewrites) under a key; portunus runs one election per key, and the elected
owner starts that child under a local Erlang/OTP supervisor.
remove/2 stops the local election; the child is gone cluster-wide once every node that
added it calls remove/2, and a remove/2 on the owner alone moves the
child to another node.
No new replicated state: the registry holds only local election pids and
a local supervisor. Restart is local and per-child, with one exception: a
child that crash-loops past the local supervisor's intensity takes the
registry down with {local_sup_down, _}, and the restarted registry is
empty: the host re-adds its children, as it does after a node restart.
The registry's cleanup releases cluster-wide locks, so a child spec
supervising it should give it a generous shutdown value.
Summary
Functions
Register ChildSpec under its child id. Only one instance of it can run
in the cluster at any given time.
Register ChildSpec under Key. Only one instance of it can run in the
cluster at any given time. Validated
at registration: an invalid spec, a re-add with a different spec, or a
child id already used under another key is an error, not a later
elect-and-fail loop. Re-adding the identical spec is idempotent.
The keys this node is contending for.
Keys for which this node is currently the elected owner.
Stop and forget the child keyed by Key on this node. The key is only
gone cluster-wide once every node that added it calls remove/2; removing
it on the owner alone moves the child to another contender.
Like start_link/2, but registers the registry process under ServerName
(e.g. {local, shovel_registry}) so add/3, remove/2 and the rest can
address it by that name instead of a pid.
If this node currently owns Key, hand ownership to TargetNode; if not,
return {error, not_owner}. Only the owner can transfer. If
TargetNode is not a ready contender the owner keeps running and the reply is
{error, {no_contender, TargetNode}}, never a handoff to some other node.
The children this node currently runs (it was elected for), in
supervisor:which_children/1 shape [{Id, Child, Type, Modules}].
Types
-type registry_opts() :: #{ttl_ms => pos_integer(), sup_flags => supervisor:sup_flags(), affinity => portunus_affinity:spec(), group => term()}.
-type server() :: gen_server:server_ref().
Functions
-spec add(server(), portunus_delayed_restart:child_spec_in()) -> ok | {error, add_error()}.
Register ChildSpec under its child id. Only one instance of it can run
in the cluster at any given time.
-spec add(server(), term(), portunus_delayed_restart:child_spec_in()) -> ok | {error, add_error()}.
Register ChildSpec under Key. Only one instance of it can run in the
cluster at any given time. Validated
at registration: an invalid spec, a re-add with a different spec, or a
child id already used under another key is an error, not a later
elect-and-fail loop. Re-adding the identical spec is idempotent.
The keys this node is contending for.
Keys for which this node is currently the elected owner.
Stop and forget the child keyed by Key on this node. The key is only
gone cluster-wide once every node that added it calls remove/2; removing
it on the owner alone moves the child to another contender.
-spec start_link(portunus:name(), registry_opts()) -> {ok, pid()} | {error, term()}.
-spec start_link(gen_server:server_name(), portunus:name(), registry_opts()) -> {ok, pid()} | {error, term()}.
Like start_link/2, but registers the registry process under ServerName
(e.g. {local, shovel_registry}) so add/3, remove/2 and the rest can
address it by that name instead of a pid.
-spec stop(server()) -> ok.
-spec transfer(server(), term(), node()) -> portunus:ok_or_error({no_contender, node()} | not_owner | no_quorum).
If this node currently owns Key, hand ownership to TargetNode; if not,
return {error, not_owner}. Only the owner can transfer. If
TargetNode is not a ready contender the owner keeps running and the reply is
{error, {no_contender, TargetNode}}, never a handoff to some other node.
-spec which_children(server()) -> [{term(), pid() | restarting | undefined, worker | supervisor, [module()] | dynamic}].
The children this node currently runs (it was elected for), in
supervisor:which_children/1 shape [{Id, Child, Type, Modules}].