Hatena::ブログ(Diary)

cooldaemonの備忘録 RSSフィード

2009-03-29

Supervisor 配下のプロセスが停止した際に State を Dump し、再起動した際に State を Restore するには?

サンプルコードを書きました。gist: 91309 - GitHub

つい最近、kai_tcp_server に、現在の接続クライアント数を記録する為の Monitor プロセスを追加したのですが、現在の仕様では、何かの拍子に Monitor が落ちると接続数がリセットされてしまいます。(そのまま運用し続ければ、いつか正しい値に戻りますが・・・)

これは Supervisor が、その配下のプロセスを再起動する際に、クラッシュ直前の State を引き継ぐような仕組みを持たない為です。

簡単に思いつく回避策としては・・・

  • Supervisor に少し手を加えた新しいモジュールを作る
  • Callback:terminate/2 で State を、ファイルに保存するか他のプロセスに預ける

などでしょうか?

そんな事を悩んでいた所、Erlang の ML にタイミング良く同じ悩みを持った方が現れました。下記 URI は、その回答です。

erlang-questions- Restore state on supervisor restart

Supervisor 起動時に State 保存用の ets(or Mnesia) を起動しておけば、配下のプロセスは State を ets に保存しておけるよ。との事。

ets は起動プロセスが生き続ける限り使う事ができる為、Supervisor が ets を起動するのは理に適った方法ですし、これであれば簡単に実装できそうです。

Supervisor に監視以外のロジックを持たせると、Supervisor がクラッシュする確率が上がってしまうのではないか?とも考えましたが(Supervisor の Callback 関数にロジックを持たせるような類いの関数が存在しないのは、その為?)ets のテーブルは、プロセス内ではなくノード内に作成されるものであり、起動プロセスとは無関係な存在だったような気がする(ets:new/2 の Source を追う気力が無かったので、識者の突っ込みを希望)ので平気だろうと思い直しました。(起動プロセスが死ぬとテーブルが消える仕様は、誰にも参照されないテーブルが残り続けるのを防ぐ為の措置?)

ただ、よほど酷い使い方をしなければ、普通の State 操作やプロセスディクショナリが、速度で ets に負ける事は無い為、常に State の代わりに ets を使うのではなく、Callback:terminate/2 で State の退避先に ets を使う方が良い方法だと思います。

kai_tcp_server の Monitor の場合、erlang:monitor/2 を用いてプロセス監視を行っている為、State を引き継いだ場合は、erlang:monitor/2 を再実行する必要があります。まー、そんなに難しい話ではないので、そのうち対応したいなぁと考えてます。

サンプルコードは、後で書きます。

んー、いい加減、Erlang で仕事!とか、並列分散処理の仕事!とか、その辺が出来る職場に転職したくなってきました(w;