OTP Design Principles: Gen_Event Behaviour

阅读更多
1,事件处理原则
在OTP里,event manager是一个命名对象,它可以接收event
一个event可以是一个error、alarm或者一些应该被log的信息
在event manager里会安装一些event handler
当event manager被通知一个event时,event会被所有安装的event handler来处理
event manager实现为一个进程,而每个event handler实现为一个callback模块
event manager本质上是维护一个{Module, State}对的list,每个Module是一个event handler,State是event handler的内部状态

2,例子
将error消息输出到终端的callback模块:
-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.

将error消息写入到文件的callback模块:
-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的第三个参数
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接收以后event manager为每个event handler调用handle_event(Event, State),调用顺序为event handler添加的顺序相反的顺序
handle_event返回{ok, State1},State1是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

这将发送一个消息给event manager来删除terminal_logger这个event handler
还将调用回调方法terminal_logger:terminate([], State),参数[]为delete_handler方法的第三个参数,返回值被忽略
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

你可能感兴趣的:(erlang,otp,design,principles,gen_event,behaviour)