global_supervisor v0.1.1 GlobalSupervisor behaviour

A supervisor that dynamically distributes children across the cluster.

A GlobalSupervisor is like a DynamicSupervisor that coordinates with other GlobalSupervisors registered with the same name in the cluster to dynamically distribute children across the cluster.

A GlobalSupervisor has the same API and behaviour of a DynamicSupervisor with some minor differences to provide distributed functionality. When you start a child using start_child/2, global supervisor uses a consistent hash algorithm to decide on which node it should be started. When a node goes down, all children running on that node will be redistributed on remaining nodes. When a new node is added to the cluster global supervisor by default automatically rebalances distribution of running children.

In case of a network split each partition restarts children running on the other part assuming that part is down. Once the partition is healed, children will be rebalanced again, but rebalancing might lead to some children being started again on the same node which they started on initially. Also when auto balancing is disabled, a healed netsplit might have multiple instances of the same child running on two or more nodes. To prevent two instances of the same child stay running after a net split heals, you need to register each child process with a unique name. Local names will only prevent running multiple instances of a child on a single node, you can use :global registry or any other distributed registry to prevent running multiple instances of a child across the cluster.

temporary children once started, won't be rebalanced or moved in the cluster.

You can change consistent hash algorithm, and disable auto balancing feature using init options.

Link to this section Summary

Types

Child specification

Options given to start_link/2 and init/1

Option values used by the start* functions

Options used by the start* functions

Supported strategies

The supervisor flags returned on init

Functions

Returns a specification to start a global supervisor under a supervisor

Same as DynamicSupervisor.count_children/1 with accumulated results of all global supervisors registered with the same name in the cluster

Receives a set of options that initializes a global supervisor

Default :locator used to locate where to start/move a child

Scans all the local children and moves the ones that don't belong to the current node based on the result of :locater function

Dynamically starts a child under one of the global supervisor instances registered with the same name in the cluster

Starts a supervisor with the given options

Starts a module-based supervisor process with the given module and arg

Terminates the given child identified by pid. It can be a child running on another node

Same as DynamicSupervisor.which_children/1 with accumulated results of all global supervisors registered with the same name in the cluster

Callbacks

Callback invoked to start the supervisor and during hot code upgrades

Link to this section Types

Link to this type

child_spec()
child_spec() ::
  {{module(), atom(), [term()]}, :permanent | :transient | :temporary,
   timeout() | :brutal_kill, :worker | :supervisor, [module()] | :dynamic}

Child specification

Link to this type

init_option()
init_option() ::
  {:strategy, strategy()}
  | {:max_restarts, non_neg_integer()}
  | {:max_seconds, pos_integer()}
  | {:max_children, non_neg_integer() | :infinity}
  | {:extra_arguments, [term()]}
  | {:auto_balance, boolean()}
  | {:locator, (child_spec(), [node()] -> node())}

Options given to start_link/2 and init/1

Link to this type

option()
option() :: {:name, Supervisor.name()} | init_option()

Option values used by the start* functions

Link to this type

options()
options() :: [option(), ...]

Options used by the start* functions

Link to this type

strategy()
strategy() :: :one_for_one

Supported strategies

Link to this type

sup_flags()
sup_flags() :: %{
  strategy: strategy(),
  intensity: non_neg_integer(),
  period: pos_integer(),
  max_children: non_neg_integer() | :infinity,
  extra_arguments: [term()],
  auto_balance: boolean(),
  locator: (child_spec(), [node()] -> node())
}

The supervisor flags returned on init

Link to this section Functions

Link to this function

child_spec(opts)

Returns a specification to start a global supervisor under a supervisor.

See Supervisor.

Link to this function

count_children(supervisor)
count_children(Supervisor.supervisor()) :: %{
  specs: non_neg_integer(),
  active: non_neg_integer(),
  supervisors: non_neg_integer(),
  workers: non_neg_integer()
}

Same as DynamicSupervisor.count_children/1 with accumulated results of all global supervisors registered with the same name in the cluster.

Link to this function

init(options)
init([init_option()]) :: {:ok, sup_flags()}

Receives a set of options that initializes a global supervisor.

It accepts the same options as DynamicSupervisor.init/1 with these two additional options:

  • :locator - a function that accepts child_spec as a tuple and a list of nodes where childs can be placed on. This function should return one of the nodes in the given nodes list, and is used by the supervisor to decide where to start/move a child in the cluster. Defaults to locate/2.

  • :auto_balance - whether to automatically rebalance children when a new node is added to the cluster. Defaults to true.

Link to this function

locate(child_spec, nodes)
locate(child_spec(), [node()]) :: node()

Default :locator used to locate where to start/move a child.

It uses :erlang.phash2/2 to consistently select a node for the given child_spec.

Link to this function

rebalance(supervisor)
rebalance(Supervisor.supervisor()) :: :ok

Scans all the local children and moves the ones that don't belong to the current node based on the result of :locater function.

A global supervisor by default rebalances itself when cluster topology changes, but if you disable :auto_balance, this function can be used to manually rebalance children on each node.

Link to this function

start_child(supervisor, child_spec)

Dynamically starts a child under one of the global supervisor instances registered with the same name in the cluster.

It uses locate/2 as default :locator to decide where to start the child. :locator can be changed in init options.

Link to this function

start_link(options)
start_link(options()) :: Supervisor.on_start()

Starts a supervisor with the given options.

The :strategy is a required option and the currently supported value is :one_for_one. The remaining options can be found in the init/1 docs.

The :name option is used to group global supervisors with the same name in the cluster together, and it has to be a local name, and if not provided GlobalSupervisor will be used.

Link to this function

start_link(mod, init_arg, opts \\ [])

Starts a module-based supervisor process with the given module and arg.

Link to this function

stop(supervisor, reason \\ :normal, timeout \\ :infinity)
stop(Supervisor.supervisor(), reason :: term(), timeout()) :: :ok

Same as DynamicSupervisor.stop/3.

Link to this function

terminate_child(supervisor, pid)
terminate_child(Supervisor.supervisor(), pid()) :: :ok | {:error, :not_found}

Terminates the given child identified by pid. It can be a child running on another node.

If successful, this function returns :ok. If there is no process with the given PID, this function returns {:error, :not_found}.

Link to this function

which_children(supervisor)
which_children(Supervisor.supervisor()) :: [
  {:undefined, pid() | :restarting, :worker | :supervisor,
   [module()] | :dynamic}
]

Same as DynamicSupervisor.which_children/1 with accumulated results of all global supervisors registered with the same name in the cluster.

Link to this section Callbacks

Link to this callback

init(init_arg)
init(init_arg :: term()) :: {:ok, sup_flags()} | :ignore

Callback invoked to start the supervisor and during hot code upgrades.

Developers typically invoke GlobalSupervisor.init/1 at the end of their init callback to return the proper supervision flags.