OTP Design Principles: Gen_Event Behaviour

4575 ワード

1、事件処理の原則
OTPではevent managerはeventを受信できる名前付きオブジェクトです
イベントはerror、alarm、またはlogされるべき情報であってもよい
event managerにはevent handlerがインストールされます
event managerがeventを通知されると、eventはすべてのインストールされたevent handlerによって処理されます.
event managerはプロセスとして実装され、各event handlerはcallbackモジュールとして実装される
event managerは本質的に{Module,State}ペアのリストを維持し、各Moduleはevent handlerであり、Stateはevent handlerの内部状態である.
2、例
端末のcallbackモジュールにerrorメッセージを出力します.

-module(terminal_logger).
-behaviour(gen_event).

-export([init/1, handle_event/2, terminate/2).

init(_Args) ->
  {ok, []}.

handle_event(ErrorMsg, State) ->
  io:format("***Error*** ~p~n", [ErrorMsg]),
  {ok, State}.

terminate(_Args, _State) ->
  ok.

ファイルのcallbackモジュールにerrorメッセージを書き込みます.

-module(file_logger).
-behaviour(gen_event).

-export([init/1, handle_event/2, terminate/2]).

init(File) ->
  {ok, Fd} = file:open(File, read).
  {ok, Fd}.

handle_event(ErrorMsg, Fd) ->
  io:format(Fd, "***Error*** ~p~n", [ErrorMsg]),
  {ok, Fd}.

terminate(_Args, Fd) ->
  file:close(Fd).

3 event managerを起動
event managerを起動してerrorを処理するには、次の方法を呼び出す必要があります.

gen_event:start_link({local, error_man})

このメソッドは新しいevent managerプロセスを起動し、接続します.
パラメータ{local,error_man}名前を指定します.ここでevent managerはローカルでerrorとして登録されています.man
gen_event:startは独立したevent managerを起動し、supervisorはありません.
4,event handlerの追加
event managerを起動し、event handlerを追加する例です.

1> gen_event:start({local, error_man}).
{ok,<0.31.0>}
2> gen_event:add_handler(error_man, terminal_logger, []).
ok

gen_event:add_handlerはevent handerを追加するために使用されます
event managerはcallbackメソッドterminalを呼び出します.logger:init([])、パラメータ[]はadd_handlerの3番目のパラメータ
initは{ok,State}を返し,Stateはevent handlerの内部状態である.

init(_Args) ->
  {ok, []}.

init(File) ->
  {ok, Fd} = file:open(File, read),
  {ok, Fd}.

5,通知event

3> gen_event:notify(error_man, no_reply).
***Error*** no_reply
ok

error_manはevent managerの名前、no_replyはevent
イベントはイベントマネージャにメッセージとして送信されます
event受信後event managerはevent handlerごとにhandle_を呼び出すevent(Event,State)、呼び出し順序event handlerが追加した順序とは逆の順序
handle_イベントは{ok,State 1}を返し,State 1はevent handlerの新しい状態である.

handle_event(ErrorMsg, State) ->
  io:format("***Error*** ~p~n", [ErrorMsg]),
  {ok, State}.

handle_event(ErrorMsg, Fd) ->
  io:format(Fd, "***Error*** ~p~n", [ErrorMsg]),
  {ok, Fd}.

6,event handlerの削除

gen_event:delete_handler(error_man, terminal_logger, []).
ok

イベントマネージャにメッセージを送信してterminalを削除します.loggerこのevent handler
コールバックメソッドterminal_も呼び出されます.logger:terminate([],State)、パラメータ[]はdelete_handlerメソッドの3番目のパラメータは、戻り値が無視されます.

terminate(_Args, _State) ->
  ok.

terminate(_Args, Fd) ->
  file:close(Fd).

7、停止
event mangerが停止すると、event handlerごとにterminate/2が呼び出されます.
7.1 supervision treeで
stopメソッドは不要
7.2独立したevent manager
stopメソッドを呼び出してevent managerを停止できます

> gen_event:stop(error_man).
ok

補足:gen_event exports and callbacks

gen_event module                             Callback module
gen_event:start_link
gen_event:start
gen_event:add_handler ----------------------> Module:init/1
gen_event:add_suphandler
gen_event:notify ---------------------------> Module:handle_event/2
gen_event:sync_notify
gen_event:call -----------------------------> Module:handle_call/2
gen_event:delete_handler -------------------> Module:terminate/2
gen_event:swap_handler ---------------------> Module1:terminate/2 Module2:init/1
gen_event:swap_sup_handler
gen_event:which_handlers
gen_event:stop -----------------------------> Module:terminate/2
                                              Module:handle_info/2
                                              Module:code_change/3