34
第4回 - プロセスだ 2 - GMO Pepabo, Inc. Joe Honzawa 2015/6/3 Elixir勉強会 Elixirだ

Elixirだ 第4回

  • Upload
    joenoh

  • View
    109

  • Download
    4

Embed Size (px)

Citation preview

第4回 - プロセスだ 2 -

GMO Pepabo, Inc. Joe Honzawa

2015/6/3 Elixir勉強会

Elixirだ

前回やったこと> Erlangプロセス > メッセージング > 状態を持ったプロセス > GenServer > Agent > Task

今回の内容> モニタとリンク > supervisor

ゴール> 理解しよう > モニタとリンクの違い > Supervision Treeの概念

モニタとリンク

プロセスは死ぬ> プロセスが死ぬとき > 予定通りに殺す場合 > 予定通りなので問題無し > 想定外の要因で死ぬ場合 > どう対処する?

死は避けられぬ>並列分散処理は複雑 >エラー処理はもっと複雑

>死んだことが検知できればよい > Let it crash > Fail fast

モニタ> プロセスAがプロセスBを監視する > Bが死んだらAが気づく > Aにメッセージが届く

pid = spawn fn -> … end Process.monitor pid

訃報{ :DOWN, #Reference<0.0.0.204>, :process, #PID<0.97.0>, { %RuntimeError{message: “…”}, [{:erlang, :apply, 2, []}] } }

> プロセス<0.97.0>が落ちた

リンク> プロセスAとプロセスBが監視しあう > Bが死んだらAも死ぬ > Aが死んだらBも死ぬ

pid = spawn fn -> … end Process.link pid

リンクさせる$ iex

iex(1)> pid = spawn fn -> ...(1)> :timer.sleep 20000 ...(1)> raise RuntimeError ...(1)> end

iex(2)> Process.link pid

iexが共倒れして再起動する

spawn_link

> spawn直後に死んだら > ちゃんとリンクできない > spawnと同時にlinkする

pid = spawn fn -> … end Process.link pid

pid = spawn_link fn -> … end

解除

Process.demonitor(pid)

Process.unlink(pid)

supervisor

ところでさっき> iexが再起動した > なぜ再起動した? > 復活させる仕組みがある > supervisor

supervisor> OTPのひとつ > 子プロセスを死活監視する > 再起動戦略 > one_for_one > one_for_all > rest_for_one > simple_one_for_one

再起動戦略> one_for_one > 1個死ぬ > 死んだ奴を復活させる

> one_for_all > 1個死ぬ > 他プロセスも全て再起動

再起動戦略> rest_for_one > 1個死ぬ > 死んだ奴より後に起動したプロセスを全て再起動

> simple_one_for_one > 基本はone_for_one > 1種類の子プロセスしか持てない

supervision treeS

C SC

SC

C

考えるな感じろ

iex> :observer.start

Applicationsタブを見てね

つくるぞ!

$ mix new --sup echo $ cd ./echo

lib/echo.exdef start(_type, _args) do import Supervisor.Spec, warn: false

children = [worker(Echo.Server, [])]

opts = [ strategy: :one_for_one, name: Echo.Supervisor ] Supervisor.start_link(children, opts) end

lib/echo/server.exdefmodule Echo.Server do alias GenServer, as: GS alias EchoServer, as: ES use GS

def start_link do GS.start_link(ES, [], name: ES) end

lib/echo/server.ex def crash! do GS.cast(ES, :crash) end

def handle_cast(:crash, _) do raise RuntimeError, message: “Oops!” end

lib/echo/server.ex def echo(term) do GS.call(ES, {:echo, term}) end

def handle_call({:echo, str}, _, s) do {:reply, str, s} end end

うごくぞ!

$ iex -S mix

iex(1)> Echo.Server.echo "hey" “hey"

落とす!

iex(2)> Echo.Server.crash! [error] … terminating

生きてる!!

iex(3)> Echo.Server.echo "yeah" "yeah"

復活の儀>生かされている > one_for_one

>何度殺しても復活する >やってみよう >息の根を止めるには?

lib/echo.exdef start(_type, _args) do # 中略 opts = [ strategy: :one_for_one, name: Echo.Supervisor, max_restarts: 2, max_seconds: 10 ] Supervisor.start_link(children, opts) end

lib/echo.exdef start(_type, _args) do # 中略 opts = [ strategy: :one_for_one, name: Echo.Supervisor, max_restarts: 2, max_seconds: 10 ] Supervisor.start_link(children, opts) end

10秒間に2回までしか 再起動しない

息の根を止めろ> 急いで3回殺してみる

iex(1)> Echo.Server.crash! iex(2)> Echo.Server.crash! iex(3)> Echo.Server.crash!

[info] Application echo exited: shutdown

プロセスだ 総復習> Fibonacci.Server > one_for_oneで監視 > Fibonacci.next/0 > 0, 1, 1, 2, 3, 5, 8 > 13は返さず死ぬ > RuntimeError

今回やったこと> モニタとリンク > supervisor