[erlang-questions] release_handler and documentation of supervisor's child spec

Serge Aleynikov saleyn@REDACTED
Sun Aug 19 15:39:09 CEST 2007


To: OTP maintainers of the 'supervisor' documentation and SASL's release 
handler.

1. The documentation of child specification of a supervisor states:

<quote chapter="Design Principles">
{Id, StartFunc, Restart, Shutdown, Type, Modules}
     ...
     Modules = [Module] | dynamic
         Module = atom()

Modules should be a list with one element [Module], where Module 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, Modules 
should be dynamic.
</quote>

<quote chapter="stdlib/supervisor/Supervision Principles">
Modules is used by the release handler during code replacement to 
determine which processes are using a certain module. As a rule of thumb 
Modules should be a list with one element [Module], where Module is the 
callback module, if the child process is a supervisor, gen_server or 
gen_fsm. If the child process is an event manager (gen_event) with a 
dynamic set of callback modules, Modules should be dynamic. See OTP 
Design Principles for more information about release handling.
</quote>

What neither reference mentions is the fact that if the child process is 
*not* a supervisor, gen_server, gen_fsm, nor gen_event, what the 
requirements are for the process when the Modules parameter is set to 
'dynamic'.  An example could be a module implemented using proc_lib. 
Unless implemented correctly release_handler won't be able to upgrade it 
properly.

It looks like the requirement is that the supervised process must 
implement get_modules/0 function that should return a list of modules 
(with at least one item) it executes as a call_back or process module.

2. The release_handler_1:get_procs/2 does the following call:

get_procs([{Name, Pid, worker, dynamic} | T], Sup) when pid(Pid) ->
     Mods = get_dynamic_mods(Name),
     ...

Shouldn't this instead be the following?

     Mods = get_dynamic_mods(Pid),
     ...

The current implementation mandates that the registered name of a 
dynamic process must match the supervisor's chiled specification ID 
(which is a name that is used to identify the child specification 
internally by the supervisor).  This mandate is somewhat odd for custom 
processes implemented using proc_lib.

To illustrate this point, I had the following code in the LAMA 
application on jungerl:

init([AlarmOptions, SyslogOpts]) ->
     SafeSupervisor =
         {lama_safe_sup,
             {supervisor, start_link,
                 [{local, lama_sup_safe}, ?MODULE,
                  {safe, AlarmOptions, SyslogOpts}]},
             permanent, infinity, supervisor, [?MODULE]},
     %% Reboot node if lama_logger or lama_alarmer or lama_snmp_trapper 
crashes!
     {ok, {_SupFlags = {one_for_one, 0, 1}, [SafeSupervisor]}};

init({safe, AlarmOptions, SyslogOpts}) ->
     SyslogH =
         {lama_syslog_sup,
             {lama_guard, start_link,
                 [lama_guard_syslog, lama_syslog_h, SyslogOpts]},
             permanent, 2000, worker, dynamic},
     AlarmH =
         {lama_alarm_sup,
             {lama_guard, start_link,
                 [lama_guard_alarm, lama_alarm_h, AlarmOptions]},
             permanent, 2000, worker, dynamic},
     {ok, {_SupFlags = {one_for_one, 4, 3600}, [SyslogH, AlarmH]}}.

The lama_guard:start_link/1 is implemented like this:

start_link(GuardName, HandlerModule, Options) ->
     Self = self(),
     proc_lib:start_link(?MODULE, init, [GuardName, HandlerModule, 
Options, Self], infinity).

init(GuardName, HandlerModule, Options, Parent) ->
     case catch erlang:register(GuardName, self()) of
     true ->
         ....

We see here that the registered name of the lama_guard process is 
determined dynamically by the GuardName parameter as the same module is 
reused for two implementations.  This presents a problem with 
'lama_syslog_sup' and 'lama_alarm_sup' child specification IDs above if 
we don't give the same name to the supervisor's child spec as the name 
registered by the spawned processes 'lama_guard_syslog' and 
'lama_guard_alarm'.  So we have to rewrite the spec as:

     SyslogH =
         {lama_guard_syslog,
          ^^^^^^^^^^^^^^^^^
             {lama_guard, start_link,
                 [lama_guard_syslog, lama_syslog_h, SyslogOpts]},
                  ^^^^^^^^^^^^^^^^^
             permanent, 2000, worker, dynamic},
     AlarmH =
         {lama_guard_alarm,
          ^^^^^^^^^^^^^^^^
             {lama_guard, start_link,
                 [lama_guard_alarm, lama_alarm_h, AlarmOptions]},
                  ^^^^^^^^^^^^^^^^
             permanent, 2000, worker, dynamic},

Since ID in the supervisor's child specification is documented as "used 
to identify the child specification internally by the supervisor", it 
shouldn't have any implications on the choice of registered names of 
supervised processes.

I don't know all the implications of changing

     Mods = get_dynamic_mods(Name),
to
     Mods = get_dynamic_mods(Pid),

in the release_handler_1:get_procs/2, but it looks like the right thing 
to do in addition to documenting get_modules/0 requirement.

Regards,

Serge




More information about the erlang-questions mailing list