Module dynamic_supervisor

A supervisor optimized to only start children dynamically.

Behaviours: gen_server.

Description

A supervisor optimized to only start children dynamically.

The standard supervisor module was designed to handle mostly static children that are started in the given order when the supervisor starts. A dynamic_supervisor starts with no children. Instead, children are started on demand via start_child/2 and there is no ordering between children. This allows the dynamic_supervisor to hold millions of children by using efficient data structures and to execute certain operations, such as shutting down, concurrently.

Examples

A dynamic supervisor is started with no children and often a name:

   {ok, Pid} = dynamic_supervisor:start_link([
       {name, {local, my_dynamic_supervisor}},
       {strategy, one_for_one}
   ]).

Once the dynamic supervisor is running, we can use it to start children on demand. Given this sample gen_server:

   -module(counter).
   -behaviour(gen_server).
  
   -export([start_link/1, inc/1]).
   -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
  
   start_link(Initial) ->
       gen_server:start_link(?MODULE, Initial, []).
  
   inc(Pid) ->
       gen_server:call(Pid, inc).
  
   init(Initial) ->
       {ok, Initial}.
  
   handle_call(inc, _From, Count) ->
       {reply, Count, Count + 1}.

We can use start_child/2 with a child specification to start a counter server:

   {ok, Counter1} = dynamic_supervisor:start_child(my_dynamic_supervisor,
       #{id => counter1,
         start => {counter, start_link, [0]},
         restart => permanent,
         shutdown => 5000,
         type => worker,
         modules => [counter]}).
   counter:inc(Counter1).
   %% 0
  
   {ok, Counter2} = dynamic_supervisor:start_child(my_dynamic_supervisor,
       #{id => counter2,
         start => {counter, start_link, [10]},
         restart => permanent,
         shutdown => 5000,
         type => worker,
         modules => [counter]}).
   counter:inc(Counter2).
   %% 10
  
   dynamic_supervisor:count_children(my_dynamic_supervisor).
   %% #{active => 2, specs => 2, supervisors => 0, workers => 2}

Data Types

child_spec()

child_spec() = #{id := term(), start := {module(), atom(), [term()]}, restart => restart(), shutdown => shutdown(), type => child_type(), modules => modules(), significant => boolean()}

child_type()

child_type() = worker | supervisor

init_option()

init_option() = {strategy, strategy()} | {max_restarts, non_neg_integer()} | {max_seconds, pos_integer()} | {max_children, non_neg_integer() | infinity} | {extra_arguments, [term()]}

modules()

modules() = [module()] | dynamic

restart()

restart() = permanent | transient | temporary

shutdown()

shutdown() = brutal_kill | infinity | non_neg_integer()

start_option()

start_option() = {name, atom() | {local, atom()} | {global, atom()} | {via, module(), term()}} | {timeout, timeout()} | {debug, [sys:debug_option()]} | {spawn_opt, [term()]}

strategy()

strategy() = one_for_one

sup_flags()

sup_flags() = #{strategy := strategy(), intensity => non_neg_integer(), period => pos_integer(), max_children => non_neg_integer() | infinity, extra_arguments => [term()], auto_shutdown => never}

Function Index

count_children/1Returns a map containing count values for the supervisor.
init_supervisor/1Receives a set of Options that initializes a dynamic supervisor.
start_child/2Dynamically adds a child specification to Supervisor and starts that child.
start_link/1Starts a supervisor with the given options.
start_link/3Starts a module-based supervisor process with the given Module and InitArg.
stop/1Synchronously stops the given supervisor with the given Reason.
stop/2
stop/3
terminate_child/2Terminates the given child identified by Pid.
which_children/1Returns a list with information about all children.

Function Details

count_children/1

count_children(Supervisor::pid() | atom() | {atom(), node()} | {global, atom()} | {via, module(), term()}) -> #{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:

init_supervisor/1

init_supervisor(Options::[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.

It accepts the same Options as start_link/1 (except for name) and it returns a tuple containing the supervisor options.

Example:
  init(_Arg) ->
      dynamic_supervisor:init_supervisor([{max_children, 1000}]).

start_child/2

start_child(Supervisor::pid() | atom() | {atom(), node()} | {global, atom()} | {via, module(), term()}, ChildSpec::child_spec() | {module(), term()} | module()) -> {ok, pid()} | {ok, pid(), term()} | ignore | {error, term()}

Dynamically adds a child specification to Supervisor and starts that child.

ChildSpec 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 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, then this function returns {error, max_children}.

start_link/1

start_link(Options::[init_option() | start_option()]) -> {ok, pid()} | ignore | {error, term()}

Starts a supervisor with the given options.

This function is typically not invoked directly, instead it is invoked when using a dynamic_supervisor as a child of another supervisor.

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.

Options:

start_link/3

start_link(Module::module(), InitArg::term(), Opts::[start_option()]) -> {ok, pid()} | ignore | {error, term()}

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

To start the supervisor, the init/1 callback will be invoked in the given Module, with InitArg as its argument. The init/1 callback must return a supervisor specification which can be created with the help of the init/1 function.

stop/1

stop(Supervisor::pid() | atom() | {atom(), node()} | {global, atom()} | {via, module(), term()}) -> 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.

stop/2

stop(Supervisor::pid() | atom() | {atom(), node()} | {global, atom()} | {via, module(), term()}, Reason::term()) -> ok

stop/3

stop(Supervisor::pid() | atom() | {atom(), node()} | {global, atom()} | {via, module(), term()}, Reason::term(), Timeout::timeout()) -> ok

terminate_child/2

terminate_child(Supervisor::pid() | atom() | {atom(), node()} | {global, atom()} | {via, module(), term()}, Pid::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/1

which_children(Supervisor::pid() | atom() | {atom(), node()} | {global, atom()} | {via, module(), term()}) -> [{undefined, pid() | restarting, worker | supervisor, [module()] | dynamic}]

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:


Generated by EDoc