Leader election and supervised child management backed by an external oracle.
Crown is a GenServer that coordinates leader election across an Erlang
cluster. Leadership authority is delegated to a pluggable oracle (see
Crown.Oracle) talking to the external world: a database lease or distributed
lock. Only one node holds the crown at a time even during netsplits.
The elected leader starts a supervised child (the :child_spec option) and
keeps it running for as long as leadership is held. When leadership is lost
the child is stopped and, optionally, a :follower_child_spec is started
instead. Followers monitor the leader and attempt to claim when it goes down.
Crown registers the leader globally as {Crown, name} so followers on other
nodes can discover and monitor it.
Usage
children = [
{Crown,
name: :my_worker,
oracle: {MyApp.RedisOracle, lock_key: "my_worker"},
child_spec: MyApp.SingletonWorker}
]
Supervisor.start_link(children, strategy: :one_for_one)Options
:name(atom/0) - Required. Atom used to register the process locally and, when leading, as{:global, {Crown, name}}for cross-node discoverability.:oracle- Required. A{module, opts}tuple.modulemust implementCrown.Oracle.optsare passed toCrown.Oracle.init/1.:child_spec(term/0) - Required. Child spec to start when this node holds the crown. May benilif no child is needed (though Crown's main purpose is to supervise a child). Accepts any value accepted bySupervisor.child_spec/2.:follower_child_spec(term/0) - Child spec to start when this node does not hold the crown. Defaults tonil(no follower child). The default value isnil.:claim_delay(non_neg_integer/0) - Milliseconds to wait after startup before the first claim attempt. The default value is0.:monitor_delay(non_neg_integer/0) - Milliseconds to wait between attempts to find and monitor the current leader after a failed claim. The first attempt always happens immediately (delay 0); subsequent retries use this value. Useful in environments where the cluster takes time to form. Defaults to 5000. The default value is5000.:monitor_timeout(pos_integer/0) - Maximum time in milliseconds to spend trying to find the leader before giving up and attempting to claim again. Defaults to 30000.This timeout is checked each time a
monitor_delaytick fires, so the actual elapsed time before a re-claim may exceedmonitor_timeoutby up to onemonitor_delayinterval.The default value is
30000.:monitor_leader(boolean/0) - Whentrue, nodes that fail to claim will monitor the current leader and attempt to claim when it goes down. Set tofalsein deployments where nodes cannot see each other and rely instead on oraclehandle_infocallbacks to trigger claim attempts. The default value istrue.
Telemetry
Crown emits telemetry events under the [:crown, ...] prefix. Use
attach_default_logger/1 for built-in logging or attach your own handlers.
See Crown.TelemetryLogger for the full list of events.
Summary
Functions
Attaches the built-in telemetry logger for Crown events.
Returns a specification to start this module under a supervisor.
Returns the term used to register the leader of name with :global.
Returns true when server currently holds the crown.
Starts a Crown process without linking it to the current process.
Starts a Crown process linked to the current process.
Returns the current {phase, leader_node} of server.
Stops the Crown process referenced by server.
Functions
Attaches the built-in telemetry logger for Crown events.
filters is forwarded to Crown.TelemetryLogger.attach/1 to narrow which
events are logged:
:min_log_level- only log events at or above this level.:prefixes- only log events whose name starts with one of the given prefixes, e.g.[[:crown, :leadership]].
Returns :ok.
Returns a specification to start this module under a supervisor.
See Supervisor.
Returns the term used to register the leader of name with :global.
The elected leader registers itself under this name so followers on other nodes can discover and monitor it.
Examples
iex> Crown.global_name(:my_worker)
{Crown, :my_worker}
Returns true when server currently holds the crown.
This is a convenience over status/1 that only reports leadership.
Starts a Crown process without linking it to the current process.
Accepts the same options as start_link/1 and forwards GenServer options
to GenServer.start/3. Returns {:ok, pid} on success, or one of the
GenServer.on_start/0 error values.
Starts a Crown process linked to the current process.
opts is the keyword list described under "Options" in the module
documentation. GenServer options (:name, :timeout, :debug,
:spawn_opt, :hibernate_after) may be mixed in and are forwarded to
GenServer.start_link/3. The process is registered locally under :name.
Returns {:ok, pid} on success, or one of the GenServer.on_start/0
error values. Applications usually start Crown from a supervisor through
child_spec/1 rather than calling this directly.
Returns the current {phase, leader_node} of server.
phase is one of:
:init- the process has started but not yet attempted a claim.:leading- the process holds the crown on the local node.:following- another node holds the crown and this process follows it.:finishing- the process is shutting down.
leader_node is the node currently believed to hold the crown, or nil
when no leader is known.
Stops the Crown process referenced by server.
When the process holds the crown, stopping it runs a clean shutdown: the supervised child is torn down before leadership is released through the oracle, so another node can safely claim the crown afterwards.