#elixirlang supervisor가 죽은 프로세스를 재시작하는 전략을 설명하는 예제

1 minute read

Supervising

예제를 잘 만드는 것도 능력이다. 예제 소스 코드를 짤 때마다 막막하다. 좋은 예제 소스 코드에서 좀 배워야 한다. 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의 재시작 전략을 설명하는 간단하고 좋은 예제다.