--- tags: public-tech --- # Elixir の supervisor で `:max_seconds` を真面目に考えるべき状況 ## Summary 死ぬことが想定されるプロセスの数が極端に少ない場合は、ちゃんと調整しないと意図通りに動かないかもしれない。 ## 状況 [Daidoquer2](https://github.com/ushitora-anqou/daidoquer2) において supervisor は次のような関係になっている。 ``` Application | v GuildSupSup | v GuildSup | v Guild ``` 2022/08/25 の障害発生時、Discord APIを叩く操作がすべて timeout で死んでいた。`systemctl restart daidoquer2` でこの現象は復活した。本当は、等価な操作を Daidoquer2 側で起こすべきであった。 この操作が発生しなかった第一の原因は `GuildSupSup` の `:strategy` が `:one_for_one` であったためである。したがってまず、これを `:one_for_all` に変更した。 第二の原因は `:max_seconds` の値がデフォルトのままであり、また `GuildSup` の数が極めて少なかったためである。障害発生時、`Guild` がまずどんどん死に、その結果 `GuildSup` が死んでいたが、これは 5 秒間隔で死んでいた。なぜなら `:max_seconds` のデフォルト値は 5 秒であるからである。一方で `GuildSupSup` は死んでいなかった。なぜなら、`GuildSup` は 5 秒で 3 回死ななかった(15 秒で 3 回死んでいた)ためである。したがって、`GuildSupSup` の `:max_seconds` を 15 秒より大きい値に変更した(30 秒)。 ## 考察 ハンドルするギルドがもっと多い場合には、より頻繁に大量に `GuildSup` が死ぬため、デフォルト値でも問題が無いかもしれない。`:max_seconds` など supervisor のパラメタは、想定プロセス数などを適宜考慮して、適切に決めるべきである。 それはそれとして、このような仕組みが Elixir に(正確には Erlang/OTP に)備わっていることは、それによって構成されるシステムを堅牢なものにするために大変重要なものであろう。例えば Go において、goroutine を使って各ギルドを管理するようなソフトウェアを作ることは比較的容易にできそうだが、それらで Discord API が死んでいることを検知して、大本のハンドラを再構成する方法をみつけることは、それほど自明ではない。Erlang/OTP のこの仕組みをうまく使いこなせれば、容易に堅牢なソフトウェアを作ることができそうである。 おわり。