aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/design_principles
diff options
context:
space:
mode:
Diffstat (limited to 'system/doc/design_principles')
-rw-r--r--system/doc/design_principles/appup_cookbook.xml6
-rw-r--r--system/doc/design_principles/sup_princ.xml233
2 files changed, 163 insertions, 76 deletions
diff --git a/system/doc/design_principles/appup_cookbook.xml b/system/doc/design_principles/appup_cookbook.xml
index 70c34a5a06..45f144e8b7 100644
--- a/system/doc/design_principles/appup_cookbook.xml
+++ b/system/doc/design_principles/appup_cookbook.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2013</year>
+ <year>2003</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -239,7 +239,7 @@ system_code_change(Chs, _Module, _OldVsn, _Extra) ->
<marker id="sup"></marker>
<title>Changing a Supervisor</title>
<p>The supervisor behaviour supports changing the internal state,
- i.e. changing restart strategy and maximum restart frequency
+ i.e. changing restart strategy and maximum restart intensity
properties, as well as changing existing child specifications.</p>
<p>Adding and deleting child processes are also possible, but not
handled automatically. Instructions must be given by in
@@ -267,7 +267,7 @@ system_code_change(Chs, _Module, _OldVsn, _Extra) ->
...
init(_Args) ->
- {ok, {{one_for_all, 1, 60}, ...}}.</code>
+ {ok, {#{strategy => one_for_all, ...}, ...}}.</code>
<p>The file <c>ch_app.appup</c>:</p>
<code type="none">
{"2",
diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml
index 11ef3813d6..3d7b53e339 100644
--- a/system/doc/design_principles/sup_princ.xml
+++ b/system/doc/design_principles/sup_princ.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2013</year>
+ <year>1997</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -29,14 +29,14 @@
<file>sup_princ.xml</file>
</header>
<p>This section should be read in conjunction with
- <c>supervisor(3)</c>, where all details about the supervisor
- behaviour is given.</p>
+ <seealso marker="stdlib:supervisor">supervisor(3)</seealso>, where
+ all details about the supervisor behaviour are described.</p>
<section>
<title>Supervision Principles</title>
- <p>A supervisor is responsible for starting, stopping and
+ <p>A supervisor is responsible for starting, stopping, and
monitoring its child processes. The basic idea of a supervisor is
- that it should keep its child processes alive by restarting them
+ that it shall keep its child processes alive by restarting them
when necessary.</p>
<p>Which child processes to start and monitor is specified by a
list of <seealso marker="#spec">child specifications</seealso>.
@@ -61,18 +61,59 @@ start_link() ->
supervisor:start_link(ch_sup, []).
init(_Args) ->
- {ok, {{one_for_one, 1, 60},
- [{ch3, {ch3, start_link, []},
- permanent, brutal_kill, worker, [ch3]}]}}.</code>
- <p><c>one_for_one</c> is the <seealso marker="#strategy">restart strategy</seealso>.</p>
- <p>1 and 60 defines the <seealso marker="#frequency">maximum restart frequency</seealso>.</p>
- <p>The tuple <c>{ch3, ...}</c> is a <seealso marker="#spec">child specification</seealso>.</p>
+ SupFlags = #{strategy => one_for_one, intensity => 1, period => 5},
+ ChildSpecs = [#{id => ch3,
+ start => {ch3, start_link, []},
+ restart => permanent,
+ shutdown => brutal_kill,
+ type => worker,
+ modules => [cg3]}],
+ {ok, {SupFlags, ChildSpecs}}.</code>
+ <p>The <c>SupFlags</c> variable in the return value
+ from <c>init/1</c> represents
+ the <seealso marker="#flags">supervisor flags</seealso>.</p>
+ <p>The <c>ChildSpecs</c> variable in the return value
+ from <c>init/1</c> is a list of <seealso marker="#spec">child
+ specifications</seealso>.</p>
+ </section>
+
+ <section>
+ <title>Supervisor Flags</title>
+ <p>This is the type definition for the supervisor flags:</p>
+ <code type="none"><![CDATA[
+sup_flags() = #{strategy => strategy(), % optional
+ intensity => non_neg_integer(), % optional
+ period => pos_integer()} % optional
+ strategy() = one_for_all
+ | one_for_one
+ | rest_for_one
+ | simple_one_for_one]]></code>
+ <list type="bulleted">
+ <item>
+ <p><c>strategy</c> specifies
+ the <seealso marker="#strategy">restart
+ strategy</seealso>.</p>
+ </item>
+ <item>
+ <p><c>intensity</c> and <c>period</c> specify
+ the <seealso marker="#max_intensity">maximum restart
+ intensity</seealso>.</p>
+ </item>
+ </list>
</section>
<section>
<marker id="strategy"></marker>
<title>Restart Strategy</title>
+ <p> The restart strategy is specified by
+ the <c>strategy</c> key in the supervisor flags map returned by
+ the callback function <c>init</c>:</p>
+ <code type="none">
+SupFlags = #{strategy => Strategy, ...}</code>
+ <p>The <c>strategy</c> key is optional in this map. If it is not
+ given, it defaults to <c>one_for_one</c>.</p>
+
<section>
<title>one_for_one</title>
<p>If a child process terminates, only that process is restarted.</p>
@@ -85,7 +126,7 @@ init(_Args) ->
<section>
<title>one_for_all</title>
<p>If a child process terminates, all other child processes are
- terminated and then all child processes, including
+ terminated, and then all child processes, including
the terminated one, are restarted.</p>
<marker id="sup5"></marker>
<image file="../design_principles/sup5.gif">
@@ -100,29 +141,36 @@ init(_Args) ->
process in start order -- are terminated. Then the terminated
child process and the rest of the child processes are restarted.</p>
</section>
+
+ <section>
+ <title>simple_one_for_one</title>
+ <p>See <seealso marker="#simple">simple-one-for-one
+ supervisors</seealso>.</p>
+ </section>
</section>
<section>
- <marker id="frequency"></marker>
- <title>Maximum Restart Frequency</title>
+ <marker id="max_intensity"></marker>
+ <title>Maximum Restart Intensity</title>
<p>The supervisors have a built-in mechanism to limit the number of
restarts which can occur in a given time interval. This is
- determined by the values of the two parameters <c>MaxR</c> and
- <c>MaxT</c> in the start specification returned by the callback
- function <c>init</c>:</p>
+ specified by the two keys <c>intensity</c> and
+ <c>period</c> in the supervisor flags map returned by the
+ callback function <c>init</c>:</p>
<code type="none">
-init(...) ->
- {ok, {{RestartStrategy, MaxR, MaxT},
- [ChildSpec, ...]}}.</code>
+SupFlags = #{intensity => MaxR, period => MaxT, ...}</code>
<p>If more than <c>MaxR</c> number of restarts occur in the last
- <c>MaxT</c> seconds, then the supervisor terminates all the child
+ <c>MaxT</c> seconds, the supervisor terminates all the child
processes and then itself.</p>
- <p>When the supervisor terminates, then the next higher level
+ <p>When the supervisor terminates, the next higher level
supervisor takes some action. It either restarts the terminated
- supervisor, or terminates itself.</p>
+ supervisor or terminates itself.</p>
<p>The intention of the restart mechanism is to prevent a situation
where a process repeatedly dies for the same reason, only to be
restarted again.</p>
+ <p>The keys <c>intensity</c> and <c>period</c> are optional in the
+ supervisor flags map. If they are not given, they default
+ to <c>1</c> and <c>5</c>, respectively.</p>
</section>
<section>
@@ -130,33 +178,42 @@ init(...) ->
<title>Child Specification</title>
<p>This is the type definition for a child specification:</p>
<code type="none"><![CDATA[
-{Id, StartFunc, Restart, Shutdown, Type, Modules}
- Id = term()
- StartFunc = {M, F, A}
- M = F = atom()
- A = [term()]
- Restart = permanent | transient | temporary
- Shutdown = brutal_kill | integer()>0 | infinity
- Type = worker | supervisor
- Modules = [Module] | dynamic
- Module = atom()]]></code>
+child_spec() = #{id => child_id(), % mandatory
+ start => mfargs(), % mandatory
+ restart => restart(), % optional
+ shutdown => shutdown(), % optional
+ type => worker(), % optional
+ modules => modules()} % optional</pre>
+ child_id() = term()
+ mfargs() = {M :: module(), F :: atom(), A :: [term()]}
+ modules() = [module()] | dynamic
+ restart() = permanent | transient | temporary
+ shutdown() = brutal_kill | timeout()
+ worker() = worker | supervisor]]></code>
<list type="bulleted">
<item>
- <p><c>Id</c> is a name that is used to identify the child
+ <p><c>id</c> is used to identify the child
specification internally by the supervisor.</p>
+ <p>The <c>id</c> key is mandatory.</p>
+ <p>Note that this identifier on occations has been called
+ "name". As far as possible, the terms "identifier" or "id"
+ are now used but in order to keep backwards compatibility,
+ some occurences of "name" can still be found, for example
+ in error messages.</p>
</item>
<item>
- <p><c>StartFunc</c> defines the function call used to start
+ <p><c>start</c> defines the function call used to start
the child process. It is a module-function-arguments tuple
used as <c>apply(M, F, A)</c>.</p>
<p>It should be (or result in) a call to
<c>supervisor:start_link</c>, <c>gen_server:start_link</c>,
- <c>gen_fsm:start_link</c> or <c>gen_event:start_link</c>.
+ <c>gen_fsm:start_link</c>, or <c>gen_event:start_link</c>.
(Or a function compliant with these functions, see
<c>supervisor(3)</c> for details.</p>
+ <p>The <c>start</c> key is mandatory.</p>
</item>
<item>
- <p><c>Restart</c> defines when a terminated child process should
+ <p><c>restart</c> defines when a terminated child process shall
be restarted.</p>
<list type="bulleted">
<item>A <c>permanent</c> child process is always restarted.</item>
@@ -166,12 +223,14 @@ init(...) ->
death causes the temporary process to be terminated).</item>
<item>A <c>transient</c> child process is restarted only if it
terminates abnormally, i.e. with another exit reason than
- <c>normal</c>, <c>shutdown</c> or <c>{shutdown,Term}</c>.</item>
+ <c>normal</c>, <c>shutdown</c>, or <c>{shutdown,Term}</c>.</item>
</list>
+ <p>The <c>restart</c> key is optional. If it is not given, the
+ default value <c>permanent</c> will be used.</p>
</item>
<item>
<marker id="shutdown"></marker>
- <p><c>Shutdown</c> defines how a child process should be
+ <p><c>shutdown</c> defines how a child process shall be
terminated.</p>
<list type="bulleted">
<item><c>brutal_kill</c> means the child process is
@@ -184,58 +243,78 @@ init(...) ->
terminated using <c>exit(Child, kill)</c>.</item>
<item>If the child process is another supervisor, it should be
set to <c>infinity</c> to give the subtree enough time to
- shutdown. It is also allowed to set it to <c>infinity</c>, if the
- child process is a worker.</item>
+ shut down. It is also allowed to set it to <c>infinity</c>,
+ if the child process is a worker.</item>
</list>
<warning>
- <p>Be careful by setting the <c>Shutdown</c> strategy to
+ <p>Be careful when setting the shutdown time to
<c>infinity</c> when the child process is a worker. Because, in this
situation, the termination of the supervision tree depends on the
child process, it must be implemented in a safe way and its cleanup
procedure must always return.</p>
</warning>
+ <p>The <c>shutdown</c> key is optional. If it is not given,
+ and the child is of type <c>worker</c>, the default value
+ <c>5000</c> will be used; if the child is of type
+ <c>supervisor</c>, the default value <c>infinity</c> will be
+ used.</p>
</item>
<item>
- <p><c>Type</c> specifies if the child process is a supervisor or
+ <p><c>type</c> specifies if the child process is a supervisor or
a worker.</p>
+ <p>The <c>type</c> key is optional. If it is not given, the
+ default value <c>worker</c> will be used.</p>
</item>
<item>
- <p><c>Modules</c> should be a list with one element
+ <p><c>modules</c> should be a list with one element
<c>[Module]</c>, where <c>Module</c> is the name of
the callback module, if the child process is a supervisor,
gen_server or gen_fsm. If the child process is a gen_event,
- <c>Modules</c> should be <c>dynamic</c>.</p>
+ the value shall be <c>dynamic</c>.</p>
<p>This information is used by the release handler during
upgrades and downgrades, see
<seealso marker="release_handling">Release Handling</seealso>.</p>
+ <p>The <c>modules</c> key is optional. If it is not given, it
+ defaults to <c>[M]</c>, where <c>M</c> comes from the
+ child's start <c>{M,F,A}</c>.</p>
</item>
</list>
<p>Example: The child specification to start the server <c>ch3</c>
in the example above looks like:</p>
<code type="none">
-{ch3,
- {ch3, start_link, []},
- permanent, brutal_kill, worker, [ch3]}</code>
+#{id => ch3,
+ start => {ch3, start_link, []},
+ restart => permanent,
+ shutdown => brutal_kill,
+ type => worker,
+ modules => [ch3]}</code>
+ <p>or simplified, relying on the default values:</p>
+ <code type="none">
+#{id => ch3,
+ start => {ch3, start_link, []}
+ shutdown => brutal_kill}</code>
<p>Example: A child specification to start the event manager from
the chapter about
<seealso marker="events#mgr">gen_event</seealso>:</p>
<code type="none">
-{error_man,
- {gen_event, start_link, [{local, error_man}]},
- permanent, 5000, worker, dynamic}</code>
- <p>Both the server and event manager are registered processes which
+#{id => error_man,
+ start => {gen_event, start_link, [{local, error_man}]},
+ modules => dynamic}</code>
+ <p>Both server and event manager are registered processes which
can be expected to be accessible at all times, thus they are
specified to be <c>permanent</c>.</p>
<p><c>ch3</c> does not need to do any cleaning up before
termination, thus no shutdown time is needed but
<c>brutal_kill</c> should be sufficient. <c>error_man</c> may
need some time for the event handlers to clean up, thus
- <c>Shutdown</c> is set to 5000 ms.</p>
+ the shutdown time is set to 5000 ms (which is the default
+ value).</p>
<p>Example: A child specification to start another supervisor:</p>
<code type="none">
-{sup,
- {sup, start_link, []},
- transient, infinity, supervisor, [sup]}</code>
+#{id => sup,
+ start => {sup, start_link, []},
+ restart => transient,
+ type => supervisor} % will cause default shutdown=>infinity</code>
</section>
<section>
@@ -262,16 +341,18 @@ start_link() ->
<c>supervisor:start_link({local, Name}, Module, Args)</c> or
<c>supervisor:start_link({global, Name}, Module, Args)</c>.</p>
<p>The new supervisor process calls the callback function
- <c>ch_sup:init([])</c>. <c>init</c> is expected to return
- <c>{ok, StartSpec}</c>:</p>
+ <c>ch_sup:init([])</c>. <c>init</c> shall return
+ <c>{ok, {SupFlags, ChildSpecs}}</c>:</p>
<code type="none">
init(_Args) ->
- {ok, {{one_for_one, 1, 60},
- [{ch3, {ch3, start_link, []},
- permanent, brutal_kill, worker, [ch3]}]}}.</code>
+ SupFlags = #{},
+ ChildSpecs = [#{id => ch3,
+ start => {ch3, start_link, []},
+ shutdown => brutal_kill}],
+ {ok, {SupFlags, ChildSpecs}}.</code>
<p>The supervisor then starts all its child processes according to
- the child specifications in the start specification. In this case
- there is one child process, <c>ch3</c>.</p>
+ the given child specifications. In this case there, is one child
+ process, <c>ch3</c>.</p>
<p>Note that <c>supervisor:start_link</c> is synchronous. It does
not return until all child processes have been started.</p>
</section>
@@ -303,17 +384,19 @@ supervisor:terminate_child(Sup, Id)</code>
<code type="none">
supervisor:delete_child(Sup, Id)</code>
<p><c>Sup</c> is the pid, or name, of the supervisor.
- <c>Id</c> is the id specified in the <seealso marker="#spec">child specification</seealso>.</p>
+ <c>Id</c> is the value associated with the <c>id</c> key in
+ the <seealso marker="#spec">child specification</seealso>.</p>
<p>As with dynamically added child processes, the effects of
deleting a static child process is lost if the supervisor itself
restarts.</p>
</section>
+ <marker id="simple"/>
<section>
<title>Simple-One-For-One Supervisors</title>
<p>A supervisor with restart strategy <c>simple_one_for_one</c> is
a simplified one_for_one supervisor, where all child processes are
- dynamically added instances of the same process.</p>
+ dynamically added instances of the same child specification.</p>
<p>Example of a callback module for a simple_one_for_one supervisor:</p>
<code type="none">
-module(simple_sup).
@@ -326,9 +409,13 @@ start_link() ->
supervisor:start_link(simple_sup, []).
init(_Args) ->
- {ok, {{simple_one_for_one, 0, 1},
- [{call, {call, start_link, []},
- temporary, brutal_kill, worker, [call]}]}}.</code>
+ SupFlags = #{strategy => simple_one_for_one,
+ intensity => 0,
+ period => 1},
+ ChildSpecs = [#{id => call,
+ start => {call, start_link, []},
+ shutdown => brutal_kill}],
+ {ok, {SupFlags, ChildSpecs}}.</code>
<p>When started, the supervisor will not start any child processes.
Instead, all child processes are added dynamically by calling:</p>
<code type="none">
@@ -336,7 +423,7 @@ supervisor:start_child(Sup, List)</code>
<p><c>Sup</c> is the pid, or name, of the supervisor.
<c>List</c> is an arbitrary list of terms which will be added to
the list of arguments specified in the child specification. If
- the start function is specified as <c>{M, F, A}</c>, then
+ the start function is specified as <c>{M, F, A}</c>,
the child process is started by calling
<c>apply(M, F, A++List)</c>.</p>
<p>For example, adding a child to <c>simple_sup</c> above:</p>
@@ -352,10 +439,10 @@ call:start_link(id1)</code>
supervisor:terminate_child(Sup, Pid)</code>
<p>where <c>Sup</c> is the pid, or name, of the supervisor and
<c>Pid</c> is the pid of the child.</p>
- <p>Because a <c>simple_one_for_one</c> supervisor could have many children,
- it shuts them all down at same time. So, order in which they are stopped is
- not defined. For the same reason, it could have an overhead with regards to
- the <c>Shutdown</c> strategy.</p>
+ <p>Because a <c>simple_one_for_one</c> supervisor could have many
+ children, it shuts them all down asynchronously. This means that
+ the children will do their cleanup in parallel and therefore the
+ order in which they are stopped is not defined.</p>
</section>
<section>