Elixirのsupervisor, worker, superviseヘルパーがイケメンだった
最近Elixirのことしか書いてないです。たぶんもうしばらくこんな感じです。
ErlangでOTP使うときとか、スーパーバイズしたい子供をつくるときに、child_spec
と呼ばれる書き方でどんな子供をつくるか指定します。公式のドキュメントにはこんな風に書いてあります。
child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules} Id = term() StartFunc = {M,F,A} M = F = atom() A = [term()] Restart = permanent | transient | temporary Shutdown = brutal_kill | int()>0 | infinity Type = worker | supervisor Modules = [Module] | dynamic Module = atom()
それぞれのパラメータの意味は各自お調べいただくとして、使われ方はこんな感じ。
start_pool(Name, Limit, MFA) -> ChildSpec = { Name, {ppool_sup, start_link, [Name, Limit, MFA]}, permanent, 10500, supervisor, [ppool_sup] }, supervisor:start_child(ppool, ChildSpec).
アトムが多いので割りと読むときは何とかなるんですけど、問題は書くときなんですよ。ええ。何番目に何とか覚えてられないわけですよ。ゆとりですから。
で、ここでElixirが登場するわけです。上の例と同じようなものを書くとこんな雰囲気。
def start_pool(name, limit, mfa) do child_spec = supervisor( PpoolSup, [name, limit, mfa], function: :start_link, restart: :permanent, shutdown: 10500 ) Supervisor.start_child(Ppool, child_spec) end
最初にこっちを読んで、「OTPって何ぞ?パラメータの意味わかんねー」って言ってErlangに行き、「パラメータの書き方なにこれキモッ」って言ってから戻ってきたら実はElixir超絶わかりやすかったってやつでした。意味わかんねーとか言ってごめんなさい。言わずもがなですが、key-value形式になってるのでパラメータの意味が一目瞭然なのですね。セルフドキュメントですよ。しかも後半3行(function:
からshutdown:
まで)はどんな順番で書いてもOKなので書くときのストレスも少ないのです。
もっと言うと、実はデフォルトのパラメータが当てられていたりするのです。上の例、よく見ると与えてるパラメータ減ってるんですよね。最後の[ppool_sup]
とか。そのデフォルトは以下。
[id: module, function: :start_link, restart: :permanent, shutdown: :infinity, # worker関数の場合は5000 modules: [module]]
module
にはsupervisor
関数の第一引数に与えたモジュール名がそのままスコーンと入ります。これらデフォルト値を考慮すると、function: :start_link
とrestart: :permanent
は書かなくても動作は変化しません。function: :start_link
は慣習になっているようなので省略していいでしょう。restart: :permanent
については、明示しておいた方が何かと良いと思います。削るメリットはあんまり無いです。
そしてもうひとつ、コールバック関数であるinit/1
で役立つのがsupervise/2
です。init/1
は、{:ok, supervisor_spec_tuple}
という形のタプルを返すように作らなければならないのですが、これがまたハマりそうで。ええ、ゆとりですから。
{ok, { {one_for_all, 10, 60}, children }}.
children
は前記のchild_spec
のリストです。ね。10と60の辺り、ハマりそうな臭いがします。これは、「エラー等で落ちた子供を60秒間に10回再起動させて、それでもダメだったら諦めろ」という意味なのですが、これがElixirだと、
supervise( children, strategy: :one_for_all, max_restarts: 10, max_seconds: 60 )
こう書けると。わかりやすくなってますね。もちろん後半3つは順不同。strategy
以外はデフォルト値が用意されてて、
max_restarts: 3, # v1.0.0-rc1以前は5だった max_seconds: 5
です。いい感じにErlangの覚えづらいところを隠してくれてますね。
しかしホントElixirばっかり触っててRuby(特にRails)書けなくなってきちゃいました。就職してから大丈夫なんですかね、ぼく。