スタックな OTP サーバの課題を、って思ってたらやっていたorz
サーバ実行のトラッキング
以降を確認しつつ、控えを列挙な方向です。
こうか (ちょっとハマッた)
iex(1)> {:ok,pid} = GenServer.start_link(Sequence.Server, 100, [:debug [:trace]])
以下な出力が。
** (FunctionClauseError) no function clause matching in Access.get/3
The following arguments were given to Access.get/3:
# 1
:debug
# 2
:trace
# 3
nil
Attempted function clauses (showing 5 out of 5):
def get(%module{} = container, key, default)
def get(map, key, default) when is_map(map)
def get(list, key, default) when is_list(list) and is_atom(key)
def get(list, key, _default) when is_list(list)
def get(nil, _key, default)
(elixir) lib/access.ex:316: Access.get/3
ありゃ?
リトライ
iex(1)> {:ok,pid} = GenServer.start_link(Sequence.Server, 100, [debug: [:trace]])
{:ok, #PID<0.135.0>}
できたな。。。
iex(2)> GenServer.call(pid, :next_number)
*DBG* <0.135.0> got call next_number from <0.133.0>
*DBG* <0.135.0> sent 100 to <0.133.0>, new state 101
100
iex(3)> GenServer.call(pid, :next_number)
*DBG* <0.135.0> got call next_number from <0.133.0>
*DBG* <0.135.0> sent 101 to <0.133.0>, new state 102
101
あるいは以下。
iex(5)> {:ok,pid} = GenServer.start_link(Sequence.Server, 100, [debug: [:statistics]])
{:ok, #PID<0.146.0>}
で、動作確認。
iex(6)> GenServer.call(pid, :next_number)
100
iex(7)> GenServer.call(pid, :next_number)
101
iex(8)> :sys.statistics pid, :get
{:ok,
[
start_time: {{2019, 5, 22}, {20, 33, 17}},
current_time: {{2019, 5, 22}, {20, 34, 6}},
reductions: 94,
messages_in: 2,
messages_out: 2
]}
あるいは デバッグパラメータにひも付けられたリストは、単に sys モジュールで呼ばれる関数の名前
て記載があります。on/off できる模様。
iex(9)> :sys.trace pid, true
:ok
iex(10)> GenServer.call(pid, :next_number)
*DBG* <0.146.0> got call next_number from <0.133.0>
*DBG* <0.146.0> sent 102 to <0.133.0>, new state 103
102
iex(11)> :sys.trace pid, false
:ok
iex(12)> GenServer.call(pid, :next_number)
103
これはこれは。あるいは get_status も便利、とあります。
iex(13)> :sys.get_status pid
{:status, #PID<0.146.0>, {:module, :gen_server},
[
[
"$ancestors": [#PID<0.133.0>, #PID<0.77.0>],
"$initial_call": {Sequence.Server, :init, 1}
],
:running,
#PID<0.133.0>,
[statistics: {{{2019, 5, 22}, {20, 33, 17}}, {:reductions, 21}, 4, 4}],
[
header: 'Status for generic server <0.146.0>',
data: [
{'Status', :running},
{'Parent', #PID<0.133.0>},
{'Logged events', []}
],
data: [{'State', 104}]
]
]}
サーバモニタリングツール
て、GUI 環境が必要なのか。
iex(14)> :observer.start()
20:47:51.534 [error] WX Failed loading 'wxe_driver'@'/usr/lib/erlang/lib/wx-1.8.8/priv'
{:error,
{{:load_driver,
'symbol _ZThn776_N17wxGenericListCtrl31GetSizeAvailableForScrollTargetERK6wxSize, version WXU_3.0 not defined in file libwx_gtk2u_core-3.0.so.0 with link time reference'}
,
[
{:wxe_server, :start, 1, [file: 'wxe_server.erl', line: 65]},
{:wx, :new, 1, [file: 'wx.erl', line: 115]},
{:observer_wx, :init, 1, [file: 'observer_wx.erl', line: 107]},
{:wx_object, :init_it, 6, [file: 'wx_object.erl', line: 372]},
{:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 249]}
]}}
むむむ。
インターフェースの整理
とりあえず、ここまで確認しておきたい。実装が以下。
defmodule Sequence.Server do
use GenServer
def start_link(current_number) do
GenServer.start_link(__MODULE__, current_number, name: __MODULE__)
end
def next_number do
GenServer.call __MODULE__, :next_number
end
def increment_number(delta) do
GenServer.cast __MODULE__, {:increment_number, delta}
end
def handle_call(:next_number, _from, current_number) do
{ :reply, current_number, current_number+1 }
end
def handle_cast({:increment_number, delta}, current_number) do
{ :noreply, current_number + delta}
end
def format_status(_reason, [ _pdict, state]) do
[data: [{'State', "My current state is '#{inspect state}', and I'm happy"}]]
end
def init(init_arg) do
{:ok, init_arg}
end
end
で iex -S mix
なナニを以下に。
iex(1)> Sequence.Server.start_link 123
{:ok, #PID<0.144.0>}
iex(2)> Sequence.Server.next_number
123
iex(3)> Sequence.Server.next_number
124
iex(4)> Sequence.Server.increment_number 100
:ok
iex(5)> Sequence.Server.next_number
225
iex(6)>
練習問題は明日あたりで云々な方向にて。