Elixir v1.6.5 DynamicSupervisor behaviour View Source
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 shutdown at the same time, with no guarantee
of ordering.
Examples
A dynamic supervisor is started with no children, often under a
supervisor with the 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(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(sup)
#=> %{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(arg) do
DynamicSupervisor.start_link(__MODULE__, arg, name: __MODULE__)
end
@impl true
def 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.
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(arg) do
Supervisor.start_link(__MODULE__, arg, name: __MODULE__)
end
def start_child(foo, bar, baz) do
# This will start child by calling MyWorker.start_link(initial_arg, foo, bar, baz)
Supervisor.start_child(__MODULE__, [foo, bar, baz])
end
@impl true
def init(initial_arg) do
children = [
# Or the deprecated: worker(MyWorker, [initial_arg])
%{id: MyWorker, start: {MyWorker, :start_link, [initial_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(arg) do
DynamicSupervisor.start_link(__MODULE__, 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(initial_arg) do
DynamicSupervisor.init(
strategy: :one_for_one,
extra_arguments: [initial_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.
Link to this section Summary
Types
Options given to start_link/2 and init/1
Return values of start_child functions
Option values used by the start* functions
Options used by the start* functions
Supported strategies
Functions
Returns a specification to start a dynamic supervisor under a supervisor
Returns a map containing count values for the supervisor
Receives a set of options that initializes a dynamic supervisor
Dynamically adds a child specification to supervisor and starts that child
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 child id
Returns a list with information about all children
Callbacks
Callback invoked to start the supervisor and during hot code upgrades
Link to this section Types
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/2 and init/1
Return values of start_child functions
Option values used by the start* functions
Options used by the start* functions
Supported strategies
Link to this section Functions
Returns a specification to start a dynamic supervisor under a supervisor.
See Supervisor.
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- always 1 as dynamic supervisors have a single specification: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
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 sections “Module-based supervisors”
in the module documentation for more information.
The options received by this function are also supported by start_link/2.
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_onewhich means that no other child is terminate if a child process terminates. You can learn more about strategies in theSupervisormodule docs.:max_restarts- the maximum number of restarts allowed in a time frame. Defaults to3.:max_seconds- the time frame in which:max_restartsapplies. Defaults to5.:max_children- the maximum amount of children to be running under this supervisor at the same time. When:max_childrenis exceeded,start_child/2returns{:error, :dynamic}. 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.supervisor(), :supervisor.child_spec() | {module(), term()} | module() ) :: on_start_child()
Dynamically adds a child specification to supervisor and starts that child.
child_spec should be a valid child specification. 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 a term containing information about
the error and child specification.
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()) :: 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(module(), term(), GenServer.options()) :: 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.
terminate_child(Supervisor.supervisor(), pid()) :: :ok | {:error, :not_found}
Terminates the given child identified by child id.
If successful, this function returns :ok. If there is no process with
the given PID, this function returns {:error, :not_found}.
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:undefinedfor dynamic supervisorschild- the pid of the corresponding child process or the atom:restartingif the process is about to be restartedtype-:workeror:supervisoras defined in the child specificationmodules- as defined in the child specification
Link to this section Callbacks
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.