#elixirlang supervisor가 죽은 프로세스를 재시작하는 전략을 설명하는 예제
예제를 잘 만드는 것도 능력이다. 예제 소스 코드를 짤 때마다 막막하다. 좋은 예제 소스 코드에서 좀 배워야 한다. supervisor 모듈이 자식 프로세스를 재시작하는 전략을 설명하는 괜찮은 예제를 programming phoenix 1.4 책에서 발견했다. supervisor 모듈은 자식 프로세스의 시작과 종료를 담당한다. supervisor를 계층(hierarchy)으로 구성하는 걸 supervision tree라고 부르는데, 이는 erlang의 Let It Crash 철학을 지탱하는 중요한 기둥이다.
defmodule InfoSys.Counter do
use GenServer
def start_link(initial_val) do
GenServer.start_link(__MODULE__, initial_val)
end
def init(initial_val) do
Process.send_after(self(), :tick, 1000)
{:ok, initial_val}
end
def handle_info(:tick, val) when val <= 0, do: raise("boom!")
def handle_info(:tick, val) do
IO.puts("tick #{val}")
Process.send_after(self(), :tick, 1000)
{:noreply, val - 1}
end
end
InfoSys.Counter.start_link/1
함수 인자로 받은 숫자를 1초에 하나씩 줄인다. 0이 되면 죽는다.
defmodule InfoSys.Application do
use Application
def start(_type, _args) do
children = [
Supervisor.child_spec({InfoSys.Counter, 15}, id: :long, restart: :permanent),
Supervisor.child_spec({InfoSys.Counter, 5}, id: :short, restart: :permanent),
Supervisor.child_spec({InfoSys.Counter, 10}, id: :medium, restart: :permanent)
]
opts = [strategy: :one_for_one, name: InfoSys.Supervisor]
Supervisor.start_link(children, opts)
end
end
restart 옵션은 재시작 제약을 결정한다. :permanent
, :temporary
값으로 바꿔가며 어떻게 달라지는지 설명한다. 자식 프로세스가 죽었을 때, 나머지 자식들의 처분하는 전략(strategy)을 테스트하려고 자식 프로세스를 여러 개 생성한다. :one_for_one
, :one_for_all
, :rest_for_all
값에 따라 나머지 자식들을 어떻게 하는지 확인할 수 있다.
iex> tick 5
tick 4
tick 3
tick 2
tick 1
[error] GenServer #PID < 0.119.0 > terminating
** (RuntimeError) boom!
(info_sys) lib/info_sys/counter.ex:22: InfoSys.Counter.handle_info/2
(stdlib) gen_server.erl:616: :gen_server.try_dispatch/4
(stdlib) gen_server.erl:686: :gen_server.handle_msg/6
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: :tick
State: 0
tick 5
tick 4
tick 3
...
elixir 대화형 셸인 iex로 확인할 수 있다. :one_for_one
전략에 :permanent
재시작 옵션이면 죽은 자식 프로세스를 항상 다시 시작한다.
supervisor의 재시작 전략을 설명하는 간단하고 좋은 예제다.