Erlang et les superviseurs 'simple_one_to_one'
- François
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 :
- https://www.erlang.org/doc/design_principles/sup_princ.html
- https://www.erldocs.com/r14b03/stdlib/supervisor
Have a comment? Contact me by email.