ちょろっとしたお遊び程度ですが、Supervisorによって管理されているプロセスをkillしたりしてプロセスをみてみました。書籍には載っているのですが、特に何も見ずにお遊び程度にサラでやってみたのでそのメモ、みたいな感じです。
初めに…
空のsupervisorプロジェクトを作ります。
$ mix new SupervisorTest --sup $ cd SupervisorTest $ mkdir lib/supervisor_test
$vim lib/supervisor_test/neko_supervisor.ex
defmodule SupervisorTest.Neko do
use GenServer
def start_link(opts) do
{_, name} = opts
GenServer.start_link(__MODULE__, :ok, [name: name])
end
end
$ vim lib/supervisor_test.ex
defmodule SupervisorTest do
use Application
def start(_type, _args) do
import Supervisor.Spec, warn: false
children = [
worker(SupervisorTest.Neko, [name: :neko]) # 追加
]
opts = [strategy: :one_for_one, name: SupervisorTest.Supervisor]
Supervisor.start_link(children, opts)
end
end
Supervisorの確認
Supervisor.count_children/1 を使い、親のSupervisorのしたに :neko の子workerがぶら下がっていることを確認してみます。
iex> pid = Process.whereis :SupervisorTest.Supervisor
#PID<0.99.0>
iex> Supervisor.count_children pid
%{active: 1, specs: 1, supervisors: 0, workers: 1}
iex> Supervisor.which_children pid
[{SupervisorTest.Neko, #PID<0.100.0>, :worker, [SupervisorTest.Neko]}]
workerをexitしてみる
Supervisorの one_for_one では、監視対象のプロセスが終了したら、異なるPIDを持つプロセスを起動する、というstrategyでした。Supervisorをexitしてみて、その挙動を実際に確認してみます。
iex> {_, c_pid, _, _} = Supervisor.which_children(pid) |> hd
{SupervisorTest.Neko, #PID<0.100.0>, :worker, [SupervisorTest.Neko]}
iex> Process.exit c_pid, :kill
:neko
true
Supervisorにぶら下がる子workerをみる
ここで、親のSupervisorのPIDを元に、そのしたにぶら下がっているプロセスをみてみます。
iex> Supervisor.which_children pid
[{SupervisorTest.Neko, #PID<0.107.0>, :worker, [SupervisorTest.Neko]}]
1回exitした one_for_one の子プロセスである :neko 、exitしたら再度立ち上げられていますね。ちゃんと、PIDが異なる値になって、別プロセスが立ち上がっていることも確認できました。なるほど。
子プロセスを終了させる、という意味だと、Supervisor.terminate_child/2 もあるのですが、こちらはSupervisorから終了させるので、停止させたら復活しませんでした。その後、Supervisor.restart_child/2 で再び動き始めます。なるほど。
One More Thing
Supervisorをkillしてみます。すると、Supervisorの子も全て終了していることがわかります。まぁ、そうですよね。
iex> Process.exit pid, :kill true 14:18:54.404 [info] Application supervisor_test exited: killed iex> Process.alive? pid false iex> Process.alive? c_pid false iex> Process.whereis :SupervisorTest.Supervisor nil iex> Process.whereis :neko nil
このようにSupervisorが落ちるとその子も落ちるので、Supervisorを階層でつなげて、それぞれに対しても様々なstrategyを設定できるようにすることが大事ですね。そこらへんの設計が大事で難しい、という話もElixir in Actionで触れられてたなー。
分散環境はやっぱり大局的な設計はすごく大事。