Supervisor shutdown

Ulf Wiger ulf.wiger@REDACTED
Tue Nov 25 13:27:00 CET 2003

On Tue, 25 Nov 2003 11:52:20 +0100, Gunilla Arendt 
<gunilla@REDACTED> wrote:

> And yes, there are alternative start strategies that in retrospect
> might have been better choices. For example, simply providing
> the supervisor with the name of the callback module(s) and make it
> responsible for starting its child processes the correct way.

...perhaps a good time for me to remind the adventurous that I
once wrote an alternative supervisor (super_hack.erl) that
(a) offered a different child_spec() syntax, where one specified
     the wanted behaviour instead of an {M,F,A}
(b) made it possible for a child to find out how many restarts
     had been carried out, including the reason for the first
     crash, and how far the restart had escalated.
(c) ...while being fully backward compatible.

Some code to illustrate the type of information made
available to the child during restart (non-blocking,
so it can be called during the init phase):

restart_info() ->
     #restarts{total = Total,
               recent = Recent,
               ordered = Ordered,
               escalation = Escalation,
               mode = Mode,
               intensity = Intensity,
               period = Period,
               restarts = Restarts} = get_restart_info(),
     [{total, Total},
      {recent, Recent},
      {ordered, Ordered},
      {escalation, Escalation},
      {mode, Mode},
      {maxR, Intensity},
      {maxT, Period},
      {restarts, Restarts}].

'ordered' as in 'ordered restarts', i.e. when someone calls 

This hack has been mentioned before. Perhaps I should take the hint,
but I still think it was a good idea.  (:

Here's an extract from the README file, explaining what hacks were
made to the supervisor module:

1) Support for a new ChildSpecification:

{Name, Behaviour, BehaviourOptions, SupervisionOptions}

SupervisionOptions ::= [Option]
Option ::= {child_type, worker | supervisor} |
            {restart_type, permanent | transient | temporary} |
            {shutdown, Shutdown : integer() | infinity} |
            {modules, [module()]} |
            {maxR, MaxR : integer() | undefined} |
            {maxT, MaxT : integer() | undefined}

This ChildSpec doesn't just specify a function that the supervisor should
call; it specifies the behaviour of the process. This raises the level
of abstraction of the specification, making an important modelling detail
more visible.

If maxR and maxT are specified for a child, the supervisor options
MaxR and MaxT must be specified as 'per_child'. To this end, it is also
legal for the CallbackModule:init/1 function to return:

   {ok, {Strategy, per_child}, ChildSpecs}

which is the same as:

   {ok, {Strategy, per_child, per_child}, ChildSpecs}

The reason for allowing per_child restart frequency is that different
children under a supervisor may (probably do) have different "weights",
and it is easier to specify different frequencies than creating multiple

Whether the supervisor uses the old (aggregated) restart frequency or
per_child restart frequencies can be checked by the child, using the

supervisor:restart_info(mode) -> aggregated | per_child.

Examples are found in testsup.erl and testsup2.erl

2) Added init_it/6, which is used to wrap Behaviour:init_it/6
3) This also allowed inserting restart information into the process
    dictionary of the child, and
4) adding the API functions restart_info/0 and restart_info/1.

restart_info() ->
    [{total, NoOfTotalRestartsThisChild},
     {recent, NoOfRestartsWithinMaxT},
     {ordered, NoOfOrderedRestarts},
     {escalation, Escalation},
     {mode, Mode},
     {maxR, MaxR},
     {maxT, Period},
     {restarts, [Timestamp]}]

If Mode == aggregated, then MaxR and MaxT will be the aggregated
values; otherwise, they will be the values for this particular child.

Escalation is [] if there has been no escalation; otherwise, it will be
[RestartsAtLowestLevel | EscalationAtNextHigherLevel]


And finally some example code illustrating the above

init([]) ->
     {ok, {{one_for_one, per_child, per_child},
            %% example 1: a generic server
            {testserver, gen_server,
             [{module, testserver},
              {args, []},
              {regname, {local,testserver}}],
             [{child_type, worker},
              {restart_type, permanent},
              {maxR, 3},
              {maxT, 30},
              {shutdown, 2000},
              {modules, [testserver]}]},

            %% example 2: a gen_fsm
            {testfsm, gen_fsm,
             [{module, testfsm},
              {args, []}],
             [{child_type, worker},
              {restart_type, permanent},
              {maxR, 10},
              {maxT, 30},
              {shutdown, 2000},
              {modules, [testfsm]}]},

            %% example 3: a gen_event
            {testevent, gen_event,
             [{regname, {global, testevent}}],
             [{child_type, worker},
              {restart_type, permanent},
              {maxR, 20},
              {maxT, 30},
              {shutdown, 2000},
              {modules, dynamic}]}


Ulf Wiger, Senior System Architect

More information about the erlang-questions mailing list