Erlang et les superviseurs 'simple_one_to_one'

Cet article a été précédemment publié a cette adresse http://dev.af83.io/2011/07/27/erlang-et-les-superviseurs-simple_one_to_one.html.

Lors d’un refactoring de U.C.Engine, je me suis retrouvé embêté par un problème tout bête. Devoir superviser des dizaines/centaines de processus de même type sans avoir à les nommer.

En effet dans le monde merveilleux de Erlang, vous démarrez vos processus à l’aide d’un superviseur. Celui-ci s’occupe de gérer le cycle de vie de votre processus, démarrage, extinction, redémarrage, etc …

Il y a plusieurs types de superviseur (et pas seulement deux, une histoire de bon et de mauvais que vous avez déjà trop entendu), et tous (sauf un donc) demande un identifiant unique à vos processus lors de leurs déclarations.

Ainsi voici une déclaration d’un superviseur assez classique avec un seul processus supervisé :

init([]) ->
    {ok, { {one_for_one, 10, 10},
          [{my_process, {my_process, start_link, []},
            permanent, brutal_kill, worker, [my_process]}]}}.

On constate que le type du superviseur est one_for_one et que le nom associé au processus fils sera my_process.

Je ne trouvais pas pertinent de devoir les nommer tous un par un. Il pouvait y en avoir des centaines, et il est déconseillé de créer des atoms à la volée pour des raisons de mémoire. La VM Erlang ne désalloue jamais la place prise par un atom même si celui-ci n’est plus utilisé. Un cas de déni de service assez simple.

Pour mon besoin de supervision, le bon type de superviseur est simple_one_for_one. Ce qui signifie :

  • des fils toujours du même type
  • pas de relation entre les fils (si l’un meurt, on ne tue pas ses frères)
init([]) ->
    {ok, { {simple_one_for_one, 0, 1},
          [{my_process, {my_process, start_link, ["Hello"]},
            temporary, brutal_kill, worker, [my_process]}]}}.

Sa particularité est que vous donnez la spécification du type de processus au démarrage, mais il ne va pas en créer un tout de suite. Vous devez utiliser la fonction supervisor:start_child/2 pour cela.

Args = ["world"],
supervisor:start_child(PidSup, Args).

Les arguments que vous passez à supervisor:start_child/2 seront rajoutés dans le tableau d’arguments défini dans le superviseur. my_process sera ainsi créé comme ceci:

my_process:start_link(["Hello", "world"]).

A vous la supervision massive de processus du même type !

Un peu de documentation de référence :

Have a comment? Contact me by email.