More Related Content
Similar to Elixir入門「第6回:Elixirはtry…catchを書かない~障害対応のパラダイムシフト~」 (20)
More from fukuoka.ex (12)
Elixir入門「第6回:Elixirはtry…catchを書かない~障害対応のパラダイムシフト~」
- 10. 9
3.スーパーバイザのプロセス監視、復旧
プロセス監視、再起動の例として、「ファイルを読み込み、内容を
返す」という簡単なサーバプログラムを使って説明します
defmodule Pass do
# サーバ
def cat_server() do
receive do
{ sender_pid, path } ->
{ :ok, result } = File.read( path )
send( sender_pid, { true, result } )
end
cat_server()
end
# サーバプロセス起動
def start_cat_server() do
pid = spawn( Pass, :cat_server, [] )
:global.register_name( :cat, pid )
end
# サーバを呼び出すクライアント
def cd( path ) do
send( :global.whereis_name( :cat ), { self(), path } )
listen()
end
end
lib/pass.ex ※Elixir入門 第2回「PC間で通信するアプリをサクっと書いてみる」の例と同じコードです
- 11. 10
3.スーパーバイザのプロセス監視、復旧
まず、「GenServer」という汎用モジュールを使って書き直します
(サーバとクライアントの書き分けや起動コードが不要になります)
呼び出し方は以下のように変わりますが、実行結果は同じです
defmodule PassGenServer do
use GenServer
def start_link() do
{ :ok, pid } = GenServer.start_link( __MODULE__, "" )
IO.puts( "--- PassGenServer.start_link() PID=#{inspect pid} ---" )
{ :ok, pid }
end
def handle_call( { :cat, path }, _from, _state ) do
{ :ok, result } = File.read( path )
{ :reply, result, "" }
end
end
lib/pass_genserver.ex
iex> { :ok, pid } = GenServer.start_link( PassGenServer, "" )
{:ok, #PID<0.211.0>}
iex> GenServer.call( pid, { :cat, "a.txt" } )
"I'm a.txt"
- 12. 11
3.スーパーバイザのプロセス監視、復旧
このサーバにおける「想定外」として、以下のようなパターンがあり
ますが、ここでは、存在しないファイルを指定した例を行います
異常系・・・存在しないファイルを指定、読込権限無、等
バグ・・・ファイル名が文字列で無い、長過ぎる、等
例外が発生し、サーバプロセスがダウンします
iex> GenServer.call( pid, { :cat, "b.txt" } )
** (EXIT from #PID<0.206.0>) an exception was raised:
** (MatchError) no match of right hand side value: {:error, :enoent}
(node1) lib/pass_genserver.ex:10: PassGenServer.handle_call/3
(stdlib) gen_server.erl:615: :gen_server.try_handle_call/4
(stdlib) gen_server.erl:647: :gen_server.handle_msg/5
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
14:31:55.520 [error] GenServer #PID<0.211.0> terminating
** (MatchError) no match of right hand side value: {:error, :enoent}
(node1) lib/pass_genserver.ex:10: PassGenServer.handle_call/3
(stdlib) gen_server.erl:615: :gen_server.try_handle_call/4
(stdlib) gen_server.erl:647: :gen_server.handle_msg/5
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: {:cat, "b.txt"}
- 16. 15
3.スーパーバイザのプロセス監視、復旧
では、プロセスダウン監視とプロセス再起動を試してみましょう
ログ出力順が逆転していますが、例外が発生し、GenServerが
ダウンしていますが、新たなGenServerが自動起動しています
iex> GenServer.call( :server_process, { :cat, "b.txt" } )
--- PassGenServer.start_link() PID=#PID<0.197.0> ---
** (exit) exited in: GenServer.call(:server_process, {:cat, "b.txt"}, 5000)
** (EXIT) an exception was raised:
** (MatchError) no match of right hand side value: {:error, :enoent}
(node1) lib/pass_genserver.ex:16: PassGenServer.handle_call/3
(stdlib) gen_server.erl:615: :gen_server.try_handle_call/4
(stdlib) gen_server.erl:647: :gen_server.handle_msg/5
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
(elixir) lib/gen_server.ex:774: GenServer.call/3
iex(4)>
15:22:39.965 [error] GenServer :server_process terminating
** (MatchError) no match of right hand side value: {:error, :enoent}
(node1) lib/pass_genserver.ex:16: PassGenServer.handle_call/3
(stdlib) gen_server.erl:615: :gen_server.try_handle_call/4
(stdlib) gen_server.erl:647: :gen_server.handle_msg/5
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: {:cat, "b.txt"}
State: ""