DynamicSupervisor behaviour
A supervisor that starts children dynamically.
The Supervisor
module was designed to handle mostly static children that are started in the given order when the supervisor starts. A DynamicSupervisor
starts with no children. Instead, children are started on demand via start_child/2
. When a dynamic supervisor terminates, all children are shut down at the same time, with no guarantee of ordering.
Examples
A dynamic supervisor is started with no children, a supervision strategy (the only strategy currently supported is :one_for_one
), and a name:
children = [ {DynamicSupervisor, strategy: :one_for_one, name: MyApp.DynamicSupervisor} ] Supervisor.start_link(children, strategy: :one_for_one)
The options given in the child specification are documented in start_link/1
.
Once the dynamic supervisor is running, we can start children with start_child/2
, which receives a child specification:
{:ok, agent1} = DynamicSupervisor.start_child(MyApp.DynamicSupervisor, {Agent, fn -> %{} end}) Agent.update(agent1, &Map.put(&1, :key, "value")) Agent.get(agent1, & &1) #=> %{key: "value"} {:ok, agent2} = DynamicSupervisor.start_child(MyApp.DynamicSupervisor, {Agent, fn -> %{} end}) Agent.get(agent2, & &1) #=> %{} DynamicSupervisor.count_children(MyApp.DynamicSupervisor) #=> %{active: 2, specs: 2, supervisors: 0, workers: 2}
Module-based supervisors
Similar to Supervisor
, dynamic supervisors also support module-based supervisors.
defmodule MyApp.DynamicSupervisor do # Automatically defines child_spec/1 use DynamicSupervisor def start_link(init_arg) do DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__) end @impl true def init(_init_arg) do DynamicSupervisor.init(strategy: :one_for_one) end end
See the Supervisor
docs for a discussion of when you may want to use module-based supervisors. A @doc
annotation immediately preceding use DynamicSupervisor
will be attached to the generated child_spec/1
function.
Name registration
A supervisor is bound to the same name registration rules as a GenServer
. Read more about these rules in the documentation for GenServer
.
Migrating from Supervisor's :simple_one_for_one
In case you were using the deprecated :simple_one_for_one
strategy from the Supervisor
module, you can migrate to the DynamicSupervisor
in few steps.
Imagine the given "old" code:
defmodule MySupervisor do use Supervisor def start_link(init_arg) do Supervisor.start_link(__MODULE__, init_arg, name: __MODULE__) end def start_child(foo, bar, baz) do # This will start child by calling MyWorker.start_link(init_arg, foo, bar, baz) Supervisor.start_child(__MODULE__, [foo, bar, baz]) end @impl true def init(init_arg) do children = [ # Or the deprecated: worker(MyWorker, [init_arg]) %{id: MyWorker, start: {MyWorker, :start_link, [init_arg]}} ] Supervisor.init(children, strategy: :simple_one_for_one) end end
It can be upgraded to the DynamicSupervisor like this:
defmodule MySupervisor do use DynamicSupervisor def start_link(init_arg) do DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__) end def start_child(foo, bar, baz) do # If MyWorker is not using the new child specs, we need to pass a map: # spec = %{id: MyWorker, start: {MyWorker, :start_link, [foo, bar, baz]}} spec = {MyWorker, foo: foo, bar: bar, baz: baz} DynamicSupervisor.start_child(__MODULE__, spec) end @impl true def init(init_arg) do DynamicSupervisor.init( strategy: :one_for_one, extra_arguments: [init_arg] ) end end
The difference is that the DynamicSupervisor
expects the child specification at the moment start_child/2
is called, and no longer on the init callback. If there are any initial arguments given on initialization, such as [initial_arg]
, it can be given in the :extra_arguments
flag on DynamicSupervisor.init/1
.
Summary
Types
- init_option()
Options given to
start_link/1
andinit/1
- on_start_child()
Return values of
start_child
functions- option()
Option values used by the
start*
functions- strategy()
Supported strategies
- sup_flags()
The supervisor flags returned on init
Functions
- child_spec(opts)
Returns a specification to start a dynamic supervisor under a supervisor.
- count_children(supervisor)
Returns a map containing count values for the supervisor.
- init(options)
Receives a set of
options
that initializes a dynamic supervisor.- start_child(supervisor, child_spec)
Dynamically adds a child specification to
supervisor
and starts that child.- start_link(options)
Starts a supervisor with the given options.
- start_link(mod, init_arg, opts \\ [])
Starts a module-based supervisor process with the given
module
andarg
.- stop(supervisor, reason \\ :normal, timeout \\ :infinity)
Synchronously stops the given supervisor with the given
reason
.- terminate_child(supervisor, pid)
Terminates the given child identified by
pid
.- which_children(supervisor)
Returns a list with information about all children.
Callbacks
- init(init_arg)
Callback invoked to start the supervisor and during hot code upgrades.
Types
init_option()
Specs
init_option() :: {:strategy, strategy()} | {:max_restarts, non_neg_integer()} | {:max_seconds, pos_integer()} | {:max_children, non_neg_integer() | :infinity} | {:extra_arguments, [term()]}
Options given to start_link/1
and init/1
on_start_child()
Specs
on_start_child() :: {:ok, pid()} | {:ok, pid(), info :: term()} | :ignore | {:error, {:already_started, pid()} | :max_children | term()}
Return values of start_child
functions
option()
Specs
option() :: GenServer.option()
Option values used by the start*
functions
strategy()
Specs
strategy() :: :one_for_one
Supported strategies
sup_flags()
Specs
sup_flags() :: %{ strategy: strategy(), intensity: non_neg_integer(), period: pos_integer(), max_children: non_neg_integer() | :infinity, extra_arguments: [term()] }
The supervisor flags returned on init
Functions
child_spec(opts)
Returns a specification to start a dynamic supervisor under a supervisor.
See Supervisor
.
count_children(supervisor)
Specs
count_children(Supervisor.supervisor()) :: %{ specs: non_neg_integer(), active: non_neg_integer(), supervisors: non_neg_integer(), workers: non_neg_integer() }
Returns a map containing count values for the supervisor.
The map contains the following keys:
:specs
- the number of children processes:active
- the count of all actively running child processes managed by this supervisor:supervisors
- the count of all supervisors whether or not the child process is still alive:workers
- the count of all workers, whether or not the child process is still alive
init(options)
Specs
init([init_option()]) :: {:ok, sup_flags()}
Receives a set of options
that initializes a dynamic supervisor.
This is typically invoked at the end of the init/1
callback of module-based supervisors. See the "Module-based supervisors" section in the module documentation for more information.
The options
received by this function are also supported by start_link/1
.
This function returns a tuple containing the supervisor options.
Examples
def init(_arg) do DynamicSupervisor.init(max_children: 1000, strategy: :one_for_one) end
Options
:strategy
- the restart strategy option. The only supported value is:one_for_one
which means that no other child is terminated if a child process terminates. You can learn more about strategies in theSupervisor
module docs.:max_restarts
- the maximum number of restarts allowed in a time frame. Defaults to3
.:max_seconds
- the time frame in which:max_restarts
applies. Defaults to5
.:max_children
- the maximum amount of children to be running under this supervisor at the same time. When:max_children
is exceeded,start_child/2
returns{:error, :max_children}
. Defaults to:infinity
.:extra_arguments
- arguments that are prepended to the arguments specified in the child spec given tostart_child/2
. Defaults to an empty list.
start_child(supervisor, child_spec)
Specs
start_child( Supervisor.supervisor(), Supervisor.child_spec() | {module(), term()} | module() | (old_erlang_child_spec :: :supervisor.child_spec()) ) :: on_start_child()
Dynamically adds a child specification to supervisor
and starts that child.
child_spec
should be a valid child specification as detailed in the "Child specification" section of the documentation for Supervisor
. The child process will be started as defined in the child specification.
If the child process start function returns {:ok, child}
or {:ok, child, info}
, then child specification and PID are added to the supervisor and this function returns the same value.
If the child process start function returns :ignore
, then no child is added to the supervision tree and this function returns :ignore
too.
If the child process start function returns an error tuple or an erroneous value, or if it fails, the child specification is discarded and this function returns {:error, error}
where error
is the error or erroneous value returned from child process start function, or failure reason if it fails.
If the supervisor already has N children in a way that N exceeds the amount of :max_children
set on the supervisor initialization (see init/1
), then this function returns {:error, :max_children}
.
start_link(options)
Specs
start_link([option() | init_option()]) :: 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 can also be used to register a supervisor name. The supported values are described under the "Name registration" section in the GenServer
module docs.
If the supervisor is successfully spawned, this function returns {:ok, pid}
, where pid
is the PID of the supervisor. If the supervisor is given a name and a process with the specified name already exists, the function returns {:error, {:already_started, pid}}
, where pid
is the PID of that process.
Note that a supervisor started with this function is linked to the parent process and exits not only on crashes but also if the parent process exits with :normal
reason.
start_link(mod, init_arg, opts \\ [])
Specs
start_link(module(), term(), [option()]) :: Supervisor.on_start()
Starts a module-based supervisor process with the given module
and arg
.
To start the supervisor, the init/1
callback will be invoked in the given module
, with arg
as its argument. The init/1
callback must return a supervisor specification which can be created with the help of the init/1
function.
If the init/1
callback returns :ignore
, this function returns :ignore
as well and the supervisor terminates with reason :normal
. If it fails or returns an incorrect value, this function returns {:error, term}
where term
is a term with information about the error, and the supervisor terminates with reason term
.
The :name
option can also be given in order to register a supervisor name, the supported values are described in the "Name registration" section in the GenServer
module docs.
stop(supervisor, reason \\ :normal, timeout \\ :infinity)
Specs
stop(Supervisor.supervisor(), reason :: term(), timeout()) :: :ok
Synchronously stops the given supervisor with the given reason
.
It returns :ok
if the supervisor terminates with the given reason. If it terminates with another reason, the call exits.
This function keeps OTP semantics regarding error reporting. If the reason is any other than :normal
, :shutdown
or {:shutdown, _}
, an error report is logged.
terminate_child(supervisor, pid)
Specs
terminate_child(Supervisor.supervisor(), pid()) :: :ok | {:error, :not_found}
Terminates the given child identified by pid
.
If successful, this function returns :ok
. If there is no process with the given PID, this function returns {:error, :not_found}
.
which_children(supervisor)
Specs
which_children(Supervisor.supervisor()) :: [ {:undefined, pid() | :restarting, :worker | :supervisor, :supervisor.modules()} ]
Returns a list with information about all children.
Note that calling this function when supervising a large number of children under low memory conditions can cause an out of memory exception.
This function returns a list of tuples containing:
id
- it is always:undefined
for dynamic supervisorschild
- the PID of the corresponding child process or the atom:restarting
if the process is about to be restartedtype
-:worker
or:supervisor
as defined in the child specificationmodules
- as defined in the child specification
Callbacks
init(init_arg)
Specs
init(init_arg :: term()) :: {:ok, sup_flags()} | :ignore
Callback invoked to start the supervisor and during hot code upgrades.
Developers typically invoke DynamicSupervisor.init/1
at the end of their init callback to return the proper supervision flags.
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.10.4/DynamicSupervisor.html