查看源代码 gen_event 行为 (stdlib v6.2)
通用事件处理行为。
此行为模块提供事件处理功能。它由一个通用事件管理器进程和任意数量的动态添加和删除的事件处理程序组成。
使用此模块实现的事件管理器具有一组标准的接口函数,并包含跟踪和错误报告的功能。它也适合 OTP 监督树。有关详细信息,请参阅 OTP 设计原则。
每个事件处理程序都实现为一个回调模块,该模块导出一组预定义的函数。行为函数和回调函数之间的关系如下
gen_event module Callback module
---------------- ---------------
gen_event:start
gen_event:start_monitor
gen_event:start_link -----> -
gen_event:add_handler
gen_event:add_sup_handler -----> Module:init/1
gen_event:notify
gen_event:sync_notify -----> Module:handle_event/2
gen_event:send_request
gen_event:call -----> Module:handle_call/2
- -----> Module:handle_info/2
gen_event:delete_handler -----> Module:terminate/2
gen_event:swap_handler
gen_event:swap_sup_handler -----> Module1:terminate/2
Module2:init/1
gen_event:which_handlers -----> -
gen_event:stop -----> Module:terminate/2
- -----> Module:code_change/3
由于每个事件处理程序都是一个回调模块,因此事件管理器有许多动态添加和删除的回调模块。gen_event
因此比其他行为更能容忍回调模块错误。如果已安装的事件处理程序的回调函数因 Reason
而失败,或返回错误的值 Term
,则事件管理器不会失败。它会通过调用回调函数 Module:terminate/2
来删除事件处理程序,并分别以 {error, {'EXIT', Reason}}
或 {error, Term}
作为参数。其他事件处理程序不受影响。
gen_event
进程按照 sys
中所述处理系统消息。sys
模块可用于调试事件管理器。
请注意,事件管理器会自动捕获退出信号。
如果处理程序模块中的回调函数在其返回值中指定了 hibernate
,则 gen_event
进程可以进入休眠状态(请参阅 erlang:hibernate/3
)。如果服务器预计会空闲很长时间,这会很有用。但是,请谨慎使用此功能,因为休眠意味着至少两次垃圾回收(在休眠时和唤醒后不久),并且不希望在繁忙的事件管理器处理的每个事件之间执行此操作。
请注意,当调用多个事件处理程序时,只要一个事件处理程序返回 hibernate
请求,就足以使整个事件管理器进入休眠状态。
除非另有说明,否则如果指定的事件管理器不存在或指定了错误的参数,则此模块中的所有函数都会失败。
注意
有关分布式信号的一些重要信息,请参阅 Erlang 参考手册的进程章节中的通过分布式阻塞信号部分。阻塞信号可能导致例如
gen_event
中的调用超时明显延迟。
另请参阅
概要
类型
事件管理器名称规范:local
、global
或 via
注册。
用于定位事件管理器的引用。
描述 gen_event
进程状态的映射。
可用于配置事件处理程序在启动时使用的选项。
不透明的请求标识符。有关详细信息,请参阅 send_request/3
。
不透明的请求标识符集合(request_id/0
)。
异步调用的响应超时。
函数
向事件管理器添加新的事件处理程序。
向事件管理器添加新的事件处理程序,并进行监督。
对事件处理程序进行同步调用。
检查接收到的消息是否为请求响应。
检查接收到的消息是否为集合中的请求响应。
从事件管理器删除事件处理程序。
向事件管理器发送异步事件通知。
接收请求响应。
将请求标识符存储在集合中。
创建空的请求标识符集合。
返回 ReqIdCollection
中的请求标识符的数量。
将请求标识符集合转换为列表。
向事件处理程序发送异步 call
请求。
向事件处理程序发送异步 call
请求,并将其存储在请求标识符集合中。
创建独立的事件管理器进程,可能无名。
创建独立的事件管理器进程。
创建事件管理器进程作为监督树的一部分,可能无名。
创建事件管理器进程作为监督树的一部分。
创建独立的事件管理器进程,受到监控,可能无名。
创建独立的事件管理器进程,受到监控。
停止事件管理器。
替换事件处理程序,并进行监督。
向事件管理器发送同步事件通知。
等待请求响应。
等待集合中的任何请求响应。
返回事件管理器中的所有事件处理程序。
类型
-type debug_flag() :: trace | log | statistics | debug | {logfile, string()}.
事件管理器名称规范:local
、global
或 via
注册。
{local, Name}
- 事件管理器在本地注册为Name
,使用register/2
。{global, GlobalName}
- 事件管理器在全局注册为GlobalName
,使用global:register_name/2
。如果未提供名称,则事件管理器不注册。{via, Module, ViaName}
,事件管理器在由Module
表示的注册表中注册。Module
回调应导出函数register_name/2
、unregister_name/1
、whereis_name/1
和send/2
,其行为应与global
中的相应函数相同。因此,{via, global, GlobalName}
是有效的引用。
用于定位事件管理器的引用。
引用可以是以下任何一种
- 事件管理器的 pid
Name
,如果事件管理器在本地注册{Name, Node}
,如果事件管理器在另一个节点上本地注册{global, GlobalName}
,如果事件管理器在全局注册{via, Module, ViaName}
,如果事件管理器通过替代进程注册表注册
-type format_status() :: #{state => term(), message => term(), reason => term(), log => [sys:system_event()]}.
描述 gen_event
进程状态的映射。
键是
state
- 事件处理程序的内部状态。message
- 导致事件处理程序终止的消息。reason
- 导致事件处理程序终止的原因。log
- 服务器的 sys 日志。
新的关联可能会在没有事先通知的情况下添加到状态映射中。
-type handler_args() :: term().
-type options() :: [{timeout, timeout()} | {debug, [debug_flag()]} | {spawn_opt, [proc_lib:start_spawn_option()]} | {hibernate_after, timeout()}].
可用于配置事件处理程序在启动时使用的选项。
-opaque request_id()
不透明的请求标识符。有关详细信息,请参阅 send_request/3
。
-opaque request_id_collection()
不透明的请求标识符集合(request_id/0
)。
每个请求标识符都可以与用户选择的标签关联。有关更多信息,请参阅 reqids_new/0
。
异步调用的响应超时。
用于设置等待响应的时间限制,可以使用 receive_response/2
、receive_response/3
、wait_response/2
或 wait_response/3
。使用的时间单位是 millisecond
。当前有效值
0..4294967295
- 相对于当前时间的超时(以毫秒为单位)。infinity
- 无限超时。也就是说,操作永远不会超时。{abs, Timeout}
- 绝对 Erlang 单调时间超时(以毫秒为单位)。也就是说,当erlang:monotonic_time(millisecond)
返回的值大于或等于Timeout
时,操作将超时。不允许Timeout
指定比4294967295
毫秒更远的未来时间。当您有一个与完整请求集合 (request_id_collection/0
) 相对应的响应截止日期时,使用绝对超时值来标识超时特别方便,因为您不必一遍又一遍地重新计算截止日期之前的相对时间。
回调
-callback code_change(OldVsn :: term() | {down, term()}, State :: term(), Extra :: term()) -> {ok, NewState :: term()}.
在代码更改后更新事件处理程序状态。
当在发布升级/降级期间(即,当 appup
文件中指定指令 {update, Module, Change,...}
时),为已安装的事件处理程序调用此函数以更新其内部状态。
有关更多信息,请参阅 OTP 设计原则。
对于升级,OldVsn
是 Vsn
,对于降级,OldVsn
是 {down, Vsn}
。Vsn
由回调模块 Module
的旧版本的 vsn
属性定义。如果未定义此类属性,则版本是 Beam 文件的校验和。
State
是事件处理程序的内部状态。
Extra
从更新指令的 {advanced, Extra}
部分“按原样”传递。
该函数应返回更新后的内部状态。
注意
如果在
.appup
文件中指定了Change={advanced, Extra}
的发布升级/降级时,未实现code_change/3
,则事件处理程序将因undef
错误原因而崩溃。
-callback format_status(Status) -> NewStatus when Status :: format_status(), NewStatus :: format_status().
格式化/限制状态值。
此函数由 gen_event
进程调用,以便格式化/限制服务器状态以进行调试和日志记录。
在以下情况下调用它
调用
sys:get_status/1,2
之一来获取gen_event
状态。事件处理程序异常终止,并且
gen_event
记录错误。
此回调用于限制由 sys:get_status/1,2
返回或发送到 logger
的事件处理程序的状态。
回调获取一个描述当前状态的映射 Status
,并应返回一个具有相同键的映射 NewStatus
,但它可以转换某些值。
此回调的两个可能用例是从状态中删除敏感信息,以防止其打印在日志文件中,或者压缩仅会使日志混乱的大型无关状态项。
示例:
format_status(Status) ->
maps:map(
fun(state,State) ->
maps:remove(private_key, State);
(message,{password, _Pass}) ->
{password, removed};
(_,Value) ->
Value
end, Status).
注意
此回调是可选的,因此事件处理程序模块不需要导出它。如果处理程序未导出此函数,则
gen_event
模块将直接使用处理程序状态来实现以下描述的目的。如果导出此回调但失败,为了隐藏可能敏感的数据,默认函数将改为返回
format_status/1
已崩溃的事实。
-callback format_status(Opt, StatusData) -> Status when Opt :: normal | terminate, StatusData :: [PDict | State], PDict :: [{Key :: term(), Value :: term()}], State :: term(), Status :: term().
格式化/限制状态值。
此函数由 gen_event
进程调用,以便格式化/限制服务器状态以进行调试和日志记录。
在以下情况下调用它
调用
sys:get_status/1,2
之一来获取gen_event
状态。在这种情况下,Opt
设置为原子normal
。事件处理程序异常终止,并且
gen_event
记录错误。在这种情况下,Opt
设置为原子terminate
。
此函数对于更改这些情况下事件处理程序状态的形式和外观很有用。希望更改 sys:get_status/1,2
返回值以及其状态在终止错误日志中的显示方式的事件处理程序回调模块,将导出 format_status/2
的实例,该实例返回描述事件处理程序当前状态的项。
PDict
是 gen_event
进程字典的当前值。
State
是事件处理程序的内部状态。
该函数应返回 Status
,一个更改事件处理程序当前状态详细信息的项。任何项都允许作为 Status
。 gen_event
模块按以下方式使用 Status
当调用
sys:get_status/1,2
时,gen_event
确保其返回值包含Status
,而不是事件处理程序的状态项。当事件处理程序异常终止时,
gen_event
将在事件处理程序的状态项的位置记录Status
。
此函数的一个用途是返回紧凑的替代状态表示形式,以避免在日志文件中打印大型状态项。
注意
此回调是可选的,因此事件处理程序模块不需要导出它。如果处理程序未导出此函数,则
gen_event
模块将直接使用处理程序状态来实现以下描述的目的。
-callback handle_call(Request :: term(), State :: term()) -> {ok, Reply :: term(), NewState :: term()} | {ok, Reply :: term(), NewState :: term(), hibernate} | {swap_handler, Reply :: term(), Args1 :: term(), NewState :: term(), Handler2 :: atom() | {atom(), Id :: term()}, Args2 :: term()} | {remove_handler, Reply :: term()}.
处理调用。
每当事件管理器收到使用 call/3,4
发送的请求时,将为指定的事件处理程序调用此函数以处理该请求。
Request
是 call/3,4
的 Request
参数。
State
是事件处理程序的内部状态。
返回值与 Module:handle_event/2
的返回值相同,但它们还包含项 Reply
,它是作为 call/3,4
的返回值的客户端回复。
-callback handle_event(Event :: term(), State :: term()) -> {ok, NewState :: term()} | {ok, NewState :: term(), hibernate} | {swap_handler, Args1 :: term(), NewState :: term(), Handler2 :: atom() | {atom(), Id :: term()}, Args2 :: term()} | remove_handler.
处理事件。
每当事件管理器收到使用 notify/2
或 sync_notify/2
发送的事件时,将为每个已安装的事件处理程序调用此函数以处理该事件。
Event
是 notify/2
/ sync_notify/2
的 Event
参数。
State
是事件处理程序的内部状态。
如果返回
{ok, NewState}
或{ok, NewState, hibernate}
,则事件处理程序将保留在事件管理器中,并可能更新内部状态NewState
。如果返回
{ok, NewState, hibernate}
,则事件管理器还会进入休眠状态(通过调用proc_lib:hibernate/3
),等待下一个事件发生。只要其中一个事件处理程序返回{ok, NewState, hibernate}
,整个事件管理器进程就会休眠。如果返回
{swap_handler, Args1, NewState, Handler2, Args2}
,则通过先调用Module:terminate(Args1, NewState)
,然后调用Module2:init({Args2, Term})
来用Handler2
替换事件处理程序,其中Term
是Module:terminate/2
的返回值。有关更多信息,请参阅swap_handler/3
。如果返回
remove_handler
,则通过调用Module:terminate(remove_handler, State)
删除事件处理程序。
-callback handle_info(Info :: term(), State :: term()) -> {ok, NewState :: term()} | {ok, NewState :: term(), hibernate} | {swap_handler, Args1 :: term(), NewState :: term(), Handler2 :: atom() | {atom(), Id :: term()}, Args2 :: term()} | remove_handler.
处理信息消息(常规进程消息)。
当事件管理器收到除事件或同步请求(或系统消息)之外的任何其他消息时,将为每个已安装的事件处理程序调用此函数。
Info
是收到的消息。
特别是,当进程在调用 add_sup_handler/3
后终止时,将进行此回调。附加到事件管理器的任何事件处理程序,该事件管理器又具有受监督的处理程序,都应预期 Module:handle_info({'EXIT', Pid, Reason}, State)
形状的回调。
有关 State
和可能的返回值的说明,请参阅 Module:handle_event/2
。
注意
此回调是可选的,因此回调模块不必导出它。
gen_event
模块提供了此函数的默认实现,该实现会记录有关意外的Info
消息,丢弃它并返回{ok, State}
。
-callback init(InitArgs :: term()) -> {ok, State :: term()} | {ok, State :: term(), hibernate} | {error, Reason :: term()}.
初始化事件处理程序。
每当向事件管理器添加新的事件处理程序时,都会调用此函数来初始化事件处理程序。
如果由于调用 add_handler/3
或 add_sup_handler/3
而添加了事件处理程序,则 InitArgs
是这些函数的 Args
参数。
如果由于调用 swap_handler/3
或 swap_sup_handler/3
,或者由于其他回调函数之一返回了 swap
元组而替换了另一个事件处理程序,则 InitArgs
是一个元组 {Args, Term}
,其中 Args
是函数调用/返回元组中提供的参数,Term
是终止旧事件处理程序的结果,请参阅 swap_handler/3
。
如果成功,该函数将返回 {ok, State}
或 {ok, State, hibernate}
,其中 State
是事件处理程序的初始内部状态。
如果返回 {ok, State, hibernate}
,则事件管理器将进入休眠状态(通过调用 proc_lib:hibernate/3
),等待下一个事件发生。
-callback terminate(Args :: term() | {stop, Reason :: term()} | stop | remove_handler | {error, {'EXIT', Reason :: term()}} | {error, term()}, State :: term()) -> term().
处理事件处理程序终止。
每当从事件管理器中删除事件处理程序时,都会调用此函数。它与 Module:init/1
相反,并执行任何必要的清理工作。
如果由于调用 delete_handler/3
、swap_handler/3
或 swap_sup_handler/3
而删除了事件处理程序,则 Arg
是此函数调用的 Args
参数。
如果事件处理程序与已终止且原因为 Reason
的进程具有受监管的连接,则 Arg = {stop, Reason}
。
如果由于事件管理器正在终止而删除了事件处理程序,则 Arg = stop
。
如果事件管理器是监督树的一部分,并且其主管命令其终止,则事件管理器将终止。即使它 *不是* 监督树的一部分,如果它从其父进程收到 'EXIT'
消息,它也会终止。
如果由于另一个回调函数返回了 remove_handler
或 {remove_handler, Reply}
而删除了事件处理程序,则 Arg = remove_handler
。
如果由于回调函数返回了意外的值 Term
而删除了事件处理程序,则 Arg = {error, Term}
;如果回调函数失败,则 Arg = {error, {'EXIT', Reason}}
。
State
是事件处理程序的内部状态。
该函数可以返回任何项。如果由于调用 gen_event:delete_handler/3
而删除了事件处理程序,则该函数的返回值将成为此函数的返回值。如果要通过交换替换事件处理程序,则返回值将传递给新事件处理程序的 init
函数。否则,返回值将被忽略。
注意
此回调是可选的,因此回调模块不必导出它。
gen_event
模块提供了没有清理的默认实现。
函数
向事件管理器添加新的事件处理程序。
新的事件处理程序将添加到事件管理器 EventMgrRef
。事件管理器调用 Module:init/1
来初始化事件处理程序及其内部状态。
Handler
是回调模块 Module
的名称,或一个元组 {Module, Id}
,其中 Id
是任何项。{Module, Id}
表示形式使得可以在许多事件处理程序使用相同回调模块时识别特定的事件处理程序。
Args
是作为参数传递给 Module:init/1
的任何项。
如果 Module:init/1
返回指示成功完成的正确值,则事件管理器将添加事件处理程序,并且此函数返回 ok
。如果 Module:init/1
失败并返回 Reason
或返回 {error,Reason}
,则将忽略事件处理程序,并且此函数将分别返回 {'EXIT',Reason}
或 {error,Reason}
。
向事件管理器添加新的事件处理程序,并进行监督。
新的事件处理程序将按照 add_handler/3
的方式添加,但是事件管理器还会通过链接事件处理程序和调用进程来监督连接。
如果调用进程稍后因
Reason
而终止,则事件管理器会通过调用Module:terminate/2
来删除任何受监管的事件处理程序,然后为每个剩余的处理程序调用Module:handle_info/2
。如果稍后删除事件处理程序,则事件管理器会向调用进程发送消息
{gen_event_EXIT,Handler,Reason}
。Reason
是以下之一normal
,如果事件处理程序由于调用delete_handler/3
而被删除,或者回调函数返回了remove_handler
(请参阅下文)。shutdown
,如果事件处理程序由于事件管理器正在终止而被删除。{swapped, NewHandler, Pid}
,如果进程Pid
通过调用swap_handler/3
或swap_sup_handler/3
将事件处理程序替换为另一个事件处理程序NewHandler
。- 其他
term/0
,如果事件处理程序由于错误而被删除。哪个项取决于错误。
有关参数和返回值的说明,请参阅 add_handler/3
。
-spec call(EventMgrRef :: emgr_ref(), Handler :: handler(), Request :: term(), Timeout :: timeout()) -> term().
对事件处理程序进行同步调用。
通过发送请求并等待直到收到答复或发生超时,将调用发送到安装在事件管理器 EventMgrRef
中的 Handler
。事件管理器调用 Module:handle_call/2
来处理请求。
Request
是作为参数之一传递给 Module:handle_call/2
的任何项。
Timeout
是一个大于零的整数,它指定等待答复的毫秒数,或者原子 infinity
表示无限期等待。默认为 5000。如果在指定的时间内未收到答复,则函数调用失败。
返回值 Reply
在 Module:handle_call/2
的返回值中定义。如果未安装指定的事件处理程序,则函数返回 {error, bad_module}
。如果回调函数失败并返回 Reason
或返回意外的值 Term
,则此函数将分别返回 {error, {'EXIT', Reason}}
或 {error, Term}
。
当此调用失败时,它会 退出 调用进程。退出项的形式为 {Reason, Location}
,其中 Location = {gen_event, call, ArgList}
。请参阅 gen_server:call/3
,其中描述了退出项中 Reason
的相关值。
-spec check_response(Msg, ReqId) -> Result when Msg :: term(), ReqId :: request_id(), Response :: {reply, Reply :: term()} | {error, {Reason :: term(), emgr_ref()}}, Result :: Response | no_reply.
检查接收到的消息是否为请求响应。
检查 Msg
是否是与请求标识符 ReqId
相对应的响应。请求必须由 send_request/3
发出,并且由调用此函数的同一进程发出。
如果 Msg
是与 ReqId
相对应的响应,则该响应将返回到 Reply
中。否则,此函数将返回 no_reply
,并且不进行清理。因此,必须重复调用此函数,直到返回响应为止。
如果未安装指定的事件处理程序,则函数返回 {error, bad_module}
。如果回调函数失败并返回 Reason
或返回意外的值 Term
,则此函数将分别返回 {error, {'EXIT', Reason}}
或 {error, Term}
。如果事件管理器在调用此函数之前已经死亡,即;Msg
报告服务器的死亡,则此函数将返回 {error,{Reason, EventMgrRef}}
,其中 Reason
是退出原因。
-spec check_response(Msg, ReqIdCollection, Delete) -> Result when Msg :: term(), ReqIdCollection :: request_id_collection(), Delete :: boolean(), Response :: {reply, Reply :: term()} | {error, {Reason :: term(), emgr_ref()}}, Result :: {Response, Label :: term(), NewReqIdCollection :: request_id_collection()} | no_request | no_reply.
检查接收到的消息是否为集合中的请求响应。
检查 Msg
是否是与存储在 ReqIdCollection
中的请求标识符相对应的响应。ReqIdCollection
的所有请求标识符都必须与使用 send_request/3
或 send_request/5
发出的请求相对应,并且所有请求都必须由调用此函数的进程发出。
响应中的 Label
是与响应对应的请求标识符关联的 Label
。请求标识符的 Label
在 将请求 id 存储在集合中时,或者在使用 send_request/5
发送请求时关联。
与 check_response/2
相比,与特定请求标识符关联的返回结果或异常将包装在 3 元组 {Response, Label, NewReqIdCollection}
中。Response
是 check_response/2
将会生成的值,Label
是与特定 请求标识符 关联的值,NewReqIdCollection
是可能修改过的请求标识符集合。
如果 ReqIdCollection
为空,则将返回 no_request
。
如果 Msg
与 ReqIdCollection
中的任何请求标识符都不对应,则返回 no_reply
。
如果 Delete
为 true
,则与 Label
的关联已从结果 NewReqIdCollection
中的 ReqIdCollection
中删除。如果 Delete
为 false
,则 NewReqIdCollection
将等于 ReqIdCollection
。请注意,删除关联不是免费的,并且包含已处理请求的集合仍然可以被后续调用 check_response/3
、receive_response/3
和 wait_response/3
使用。
但是,如果不删除已处理的关联,则上述调用将无法检测到何时没有更多未处理的请求需要处理,因此您必须通过其他方式来跟踪此情况,而不是依赖于 no_request
返回值。请注意,如果您将仅包含已处理或已放弃请求的关联的集合传递给 check_response/3
,它将始终返回 no_reply
。
从事件管理器删除事件处理程序。
此函数从事件管理器 EventMgrRef
中删除事件处理程序 Handler
。事件管理器调用 Module:terminate/2
来终止事件处理程序。
Args
是作为参数之一传递给 Module:terminate/2
的任何项。
返回值是 Module:terminate/2
的返回值。如果未安装指定的事件处理程序,则该函数返回 {error, module_not_found}
。如果回调函数失败并返回 Reason
,则该函数返回 {'EXIT', Reason}
。
向事件管理器发送异步事件通知。
事件被发送到 EventMgrRef
,它调用 Module:handle_event/2
,为每个已安装的事件处理程序处理事件。
Event
是作为参数之一传递给 Module:handle_event/2
的任何项。
即使指定的事件管理器不存在,notify/1
也不会失败,除非它被指定为 Name
。
-spec receive_response(ReqId, Timeout) -> Result when ReqId :: request_id(), Timeout :: response_timeout(), Response :: {reply, Reply :: term()} | {error, {Reason :: term(), emgr_ref()}}, Result :: Response | timeout.
接收请求响应。
接收与请求标识符 ReqId
对应的响应。该请求必须由 send_request/3
发出,并且必须由调用此函数的同一进程发出。
Timeout
指定等待响应的时间。如果在指定的时间内未收到响应,则此函数返回 timeout
。假设服务器在支持别名(在 OTP 24 中引入)的节点上执行,则请求也将被放弃。也就是说,超时后将不会收到任何响应。否则,可能会在稍后收到错误的响应。
返回值 Reply
在 Module:handle_call/2
的返回值中定义。
如果未安装指定的事件处理程序,则此函数返回 {error, bad_module}
。如果回调函数失败并返回 Reason
或返回意外值 Term
,则此函数分别返回 {error, {'EXIT', Reason}}
或 {error,Term}
。如果事件管理器在请求之前或期间死亡,则此函数返回 {error, {Reason, EventMgrRef}}
。
wait_response/2
和 receive_response/2
之间的区别在于,receive_response/2
在超时时放弃请求,以便忽略潜在的未来响应,而 wait_response/2
则不会。
-spec receive_response(ReqIdCollection, Timeout, Delete) -> Result when ReqIdCollection :: request_id_collection(), Timeout :: response_timeout(), Delete :: boolean(), Response :: {reply, Reply :: term()} | {error, {Reason :: term(), emgr_ref()}}, Result :: {Response, Label :: term(), NewReqIdCollection :: request_id_collection()} | no_request | timeout.
接收集合中的请求响应。
在 ReqIdCollection
中接收响应。ReqIdCollection
的所有请求标识符必须对应于使用 send_request/3
或 send_request/5
发出的请求,并且所有请求必须由调用此函数的进程发出。
响应中的 Label
是与响应对应的请求标识符关联的 Label
。请求标识符的 Label
在将请求 ID 添加到集合时,或者在使用 send_request/5
发送请求时关联。
与 receive_response/2
相比,与特定请求标识符关联的返回结果或异常将包装在一个 3 元组 {Response, Label, NewReqIdCollection}
中。Response
是 receive_response/2
将产生的值,Label
是与特定 请求标识符 关联的值,NewReqIdCollection
是一个可能修改过的请求标识符集合。
如果 ReqIdCollection
为空,则将返回 no_request
。
Timeout
指定等待响应的时间。如果在指定的时间内未收到响应,则该函数返回 timeout
。假设服务器在支持别名(在 OTP 24 中引入)的节点上执行,则 ReqIdCollection
标识的所有请求也将被放弃。也就是说,超时后将不会收到任何响应。否则,可能会在稍后收到错误的响应。
receive_response/3
和 wait_response/3
之间的区别在于,receive_response/3
在超时时放弃请求,以便忽略潜在的未来响应,而 wait_response/3
则不会。
如果 Delete
为 true
,则与 Label
的关联将从结果 NewReqIdCollection
中的 ReqIdCollection
中删除。如果 Delete
为 false
,则 NewReqIdCollection
将等于 ReqIdCollection
。请注意,删除关联不是免费的,并且包含已处理请求的集合仍然可以被后续调用 receive_response/3
、check_response/3
和 wait_response/3
使用。
但是,如果不删除已处理的关联,则上述调用将无法检测到何时没有更多未处理的请求需要处理,因此您必须通过其他方式来跟踪此情况,而不是依赖于 no_request
返回值。请注意,如果您将仅包含已处理或已放弃请求的关联的集合传递给 receive_response/3
,它将始终阻塞,直到 Timeout
过期,然后返回 timeout
。
-spec reqids_add(ReqId :: request_id(), Label :: term(), ReqIdCollection :: request_id_collection()) -> NewReqIdCollection :: request_id_collection().
将请求标识符存储在集合中。
存储 ReqId
并通过将此信息添加到 ReqIdCollection
并返回结果请求标识符集合,将 Label
与请求标识符关联。
-spec reqids_new() -> NewReqIdCollection :: request_id_collection().
创建空的请求标识符集合。
返回一个新的空请求标识符集合。可以使用请求标识符集合来处理多个未完成的请求。
通过 send_request/3
发出的请求的请求标识符可以使用 reqids_add/3
保存在请求标识符集合中。稍后可以使用此类请求标识符集合,通过将集合作为参数传递给 receive_response/3
、wait_response/3
或 check_response/3
,以获取集合中与请求对应的单个响应。
reqids_size/1
可用于确定集合中请求标识符的数量。
-spec reqids_size(ReqIdCollection :: request_id_collection()) -> non_neg_integer().
返回 ReqIdCollection
中的请求标识符的数量。
-spec reqids_to_list(ReqIdCollection :: request_id_collection()) -> [{ReqId :: request_id(), Label :: term()}].
将请求标识符集合转换为列表。
返回 {ReqId, Label}
元组的列表,该列表对应于 ReqIdCollection
中所有带有其关联标签的请求标识符。
-spec send_request(EventMgrRef :: emgr_ref(), Handler :: handler(), Request :: term()) -> ReqId :: request_id().
向事件处理程序发送异步 call
请求。
此函数将调用请求 Request
发送到由 EventMgrRef
标识的事件管理器中安装的事件处理程序 Handler
,并返回请求标识符 ReqId
。返回值 ReqId
稍后应与 receive_response/2
、wait_response/2
或 check_response/2
一起使用,以获取请求的实际结果。
除了将请求标识符直接传递给这些函数之外,还可以使用 reqids_add/3
将其存储在请求标识符集合中。稍后可以使用此类请求标识符集合,通过将集合作为参数传递给 receive_response/3
、wait_response/3
或 check_response/3
,以获取集合中与请求对应的单个响应。如果要将请求标识符存储在集合中,您可能需要考虑使用 send_request/5
。
调用 gen_event:receive_response(gen_event:send_request(EventMgrRef, Handler, Request), Timeout)
可以被视为等同于 gen_event:call(EventMgrRef, Handler, Request, Timeout)
,忽略错误处理。
事件管理器调用 Module:handle_call/2
来处理请求。
Request
可以是任何项,并作为参数之一传递给 Module:handle_call/2
。
-spec send_request(EventMgrRef :: emgr_ref(), Handler :: handler(), Request :: term(), Label :: term(), ReqIdCollection :: request_id_collection()) -> NewReqIdCollection :: request_id_collection().
向事件处理程序发送异步 call
请求,并将其存储在请求标识符集合中。
此函数将调用请求 Request
发送到由 EventMgrRef
标识的事件管理器中安装的事件处理程序 Handler
。Label
将与操作的请求标识符关联,并添加到返回的请求标识符集合 NewReqIdCollection
中。
该集合稍后可用于通过将集合作为参数传递给 receive_response/3
、wait_response/3
或 check_response/3
来获取集合中与请求对应的单个响应。
与调用 gen_event:reqids_add
(
gen_event:send_request
(EventMgrRef, Handler, Request), Label, ReqIdCollection)
相同,但效率略高。
-spec start() -> start_ret().
等效于 start([])
。
创建独立的事件管理器进程,可能无名。
等效于 start(EventMgrName, Options)
。
使用参数 EventMgrName
,Options
为 []
。
使用参数 Options
创建一个无名的事件管理器。
有关参数和返回值的说明,请参阅 start_link/2
。
创建独立的事件管理器进程。
创建的事件管理器进程不属于监督树的一部分,因此没有主管。
有关参数和返回值的说明,请参阅 start_link/2
。
-spec start_link() -> start_ret().
等效于 start_link([])
。
-spec start_link(EventMgrName :: emgr_name()) -> start_ret(); (Options :: options()) -> start_ret().
创建事件管理器进程作为监督树的一部分,可能无名。
等效于 start_link(EventMgrName, Options)
。
使用参数 EventMgrName
,Options
为 []
。
使用参数 Options
创建一个无名的事件管理器。
有关参数和返回值的说明,请参阅 start_link/2
。
创建事件管理器进程作为监督树的一部分。
该函数应由主管直接或间接调用。例如,它确保事件管理器链接到调用者(主管)。
- 如果存在选项
{hibernate_after, HibernateAfterTimeout}
,则gen_event
进程会等待任何消息HibernateAfterTimeout
毫秒,如果没有收到消息,则该进程会自动进入休眠状态(通过调用proc_lib:hibernate/3
)。
如果事件管理器成功创建,该函数将返回 {ok, Pid}
,其中 Pid
是事件管理器的 pid/0
。
如果已存在具有指定 EventMgrName
的进程,该函数将返回 {error,{already_started,OtherPid}}
,其中 OtherPid
是该进程的 pid,并且事件管理器进程将以 normal
为原因退出。
如果事件管理器在指定的启动超时 {timeout, Time}
内未能启动,这种情况极不可能发生,因为启动不会与其他进程交互,则该函数将返回 {error, timeout}
,并且失败的事件管理器将以 exit(_, kill)
被终止。
如果 start_link/1,2
返回 {error, _}
,则启动的事件管理器进程已终止。如果 'EXIT'
消息已传递给调用进程(由于进程链接),则该消息已被使用。
警告
在 OTP 26.0 之前,如果启动的事件管理器未能注册其名称,则此函数可能会在启动的事件管理器进程终止之前返回
{error, {already_started, OtherPid}}
,因此再次启动可能会失败,因为注册的名称尚未注销,并且稍后可能会向调用此函数的进程发送'EXIT'
消息。但是,如果启动超时,此函数会终止启动的事件管理器进程并返回
{error, timeout}
,然后进程链接{'EXIT', Pid, killed}
消息被使用。启动在 OTP 26.0 中是同步进行的,并且保证了来自失败启动的任何进程链接
'EXIT'
消息都不会在调用者的收件箱中停留。
-spec start_monitor() -> start_mon_ret().
等效于 start_monitor([])
。
-spec start_monitor(EventMgrNameOrOptions :: emgr_name() | options()) -> start_mon_ret().
创建独立的事件管理器进程,受到监控,可能无名。
等效于 start_monitor(EventMgrName, Options)
。
使用参数 EventMgrName
,Options
为 []
。
使用参数 Options
创建一个无名的事件管理器。
有关参数和返回值的说明,请参阅 start_monitor/2
和 start_link/1
。
-spec start_monitor(EventMgtName :: emgr_name(), Options :: options()) -> start_mon_ret().
创建独立的事件管理器进程,受到监控。
创建的事件管理器进程不属于监督树的一部分,因此没有主管。原子地为新创建的进程设置一个监视器。
有关参数和返回值的说明,请参阅 start_link/2
。请注意,成功启动的返回值与 start_link/2
不同。start_monitor/0,1,2
将返回 {ok, {Pid, Mon}}
,其中 Pid
是进程的进程标识符,而 Mon
是设置为监视进程的监视器的引用。如果启动不成功,则调用者将被阻塞,直到收到 DOWN
消息并从消息队列中删除。
-spec stop(EventMgrRef :: emgr_ref()) -> ok.
停止事件管理器。
命令事件管理器 EventMgrRef
以指定的 Reason
退出,并等待其终止。在终止之前,gen_event
会为每个已安装的事件处理程序调用 Module:terminate(stop,...)
。
如果事件管理器以预期原因终止,则该函数返回 ok
。除 normal
、shutdown
或 {shutdown, Term}
之外的任何其他原因都会使用 logger
发出错误报告。
Timeout
是一个大于零的整数,用于指定等待事件管理器终止的毫秒数,或原子 infinity
以无限期等待。如果事件管理器在指定的时间内未终止,则调用将以 timeout
为原因退出调用进程。
如果进程不存在,则调用将以 noproc
为原因退出调用进程,如果与服务器运行的远程 Node
的连接失败,则以 {nodedown, Node}
为原因退出。
-spec swap_handler(EventMgrRef :: emgr_ref(), OldHandler :: {handler(), term()}, NewHandler :: {handler(), term()}) -> ok | {error, term()}.
替换事件处理程序。
此函数替换事件管理器 EventMgrRef
中的事件处理程序。
有关 OldHandler
和 NewHandler
的说明,请参阅 add_handler/3
。
首先删除旧的事件处理程序 OldHandler
。事件管理器调用 OldModule:terminate(Args1, ...)
,其中 OldModule
是 OldHandler
的回调模块,并收集返回值。
然后添加新的事件处理程序 NewHandler
,并通过调用 NewModule:init({Args2,Term})
初始化,其中 NewModule
是 NewHandler
的回调模块,Term
是 OldModule:terminate/2
的返回值。这使得可以从 OldHandler
向 NewHandler
传递信息。
即使未安装指定的旧事件处理程序(在这种情况下,Term = error
),或者 OldModule:terminate/2
因 Reason
失败(在这种情况下,Term = {'EXIT', Reason}
),也会添加新的处理程序。即使 NewModule:init/1
失败,也会删除旧的处理程序。
如果在 OldHandler
和进程 Pid
之间存在受监督的连接,则在 NewHandler
和 Pid
之间存在一个受监督的连接。
如果 NewModule:init/1
返回正确的值,则此函数将返回 ok
。如果 NewModule:init/1
因 Reason
失败或返回意外的值 Term
,则此函数将分别返回 {error, {'EXIT', Reason}}
或 {error, Term}
。
-spec swap_sup_handler(EventMgrRef :: emgr_ref(), OldHandler :: {handler(), term()}, NewHandler :: {handler(), term()}) -> ok | {error, term()}.
替换事件处理程序,并进行监督。
以与 swap_handler/3
相同的方式替换事件管理器 EventMgrRef
中的事件处理程序,但也监督 NewHandler
和调用进程之间的连接。
有关参数和返回值的说明,请参阅 swap_handler/3
。
向事件管理器发送同步事件通知。
事件被发送到 EventMgrRef
,该管理器为每个已安装的事件处理程序调用 Module:handle_event/2
来处理事件。在所有事件处理程序处理完事件后,此函数将返回 ok
。
Event
是作为参数之一传递给 Module:handle_event/2
的任何项。
-spec wait_response(ReqId, WaitTime) -> Result when ReqId :: request_id(), WaitTime :: response_timeout(), Response :: {reply, Reply :: term()} | {error, {Reason :: term(), emgr_ref()}}, Result :: Response | timeout.
等待请求响应。
等待请求标识符 ReqId
的响应。请求必须由调用 send_request/3
的同一进程通过 send_request/3
发出。
WaitTime
指定等待响应的时间。如果在指定的时间内未收到响应,则该函数将返回 timeout
且不执行清理。因此,可以重复调用该函数,直到返回响应。
返回值 Reply
在 Module:handle_call/2
的返回值中定义。
如果未安装指定的事件处理程序,则该函数将返回 {error, bad_module}
。如果回调函数因 Reason
失败或返回意外值 Term
,则此函数将分别返回 {error,{'EXIT',Reason}}
或 {error,Term}
。如果事件管理器在请求之前或期间终止,则此函数将返回 {error, {Reason, EventMgrRef}}
。
receive_response/2
和 wait_response/2
之间的区别在于,receive_response/2
会在超时时放弃请求,以便忽略潜在的未来响应,而 wait_response/2
不会。
-spec wait_response(ReqIdCollection, WaitTime, Delete) -> Result when ReqIdCollection :: request_id_collection(), WaitTime :: response_timeout(), Delete :: boolean(), Response :: {reply, Reply :: term()} | {error, {Reason :: term(), emgr_ref()}}, Result :: {Response, Label :: term(), NewReqIdCollection :: request_id_collection()} | no_request | timeout.
等待集合中的任何请求响应。
等待 ReqIdCollection
中的响应。ReqIdCollection
的所有请求标识符都必须对应于使用 send_request/3
或 send_request/5
发出的请求,并且所有请求都必须由调用此函数的进程发出。
响应中的 Label
是与响应对应的请求标识符关联的 Label
。请求标识符的 Label
在将请求 ID 添加到集合时,或者在使用 send_request/5
发送请求时关联。
与 wait_response/2
相比,与特定请求标识符关联的返回结果或异常将封装在 3 元组 {Response, Label, NewReqIdCollection}
中。Response
是 wait_response/2
将产生的值,Label
是与特定 请求标识符 关联的值,而 NewReqIdCollection
是可能修改过的请求标识符集合。
如果 ReqIdCollection
为空,则将返回 no_request
。
如果在 WaitTime
过期之前没有收到响应,则返回 timeout
。在收到响应并通过 check_response()
、receive_response()
或 wait_response()
完成响应之前,可以根据需要多次继续等待响应。
receive_response/3
和 wait_response/3
之间的区别在于,receive_response/3
在超时时放弃请求,以便忽略潜在的未来响应,而 wait_response/3
则不会。
如果 Delete
为 true
,则与 Label
的关联已从结果 NewReqIdCollection
中的 ReqIdCollection
中删除。如果 Delete
为 false
,则 NewReqIdCollection
将等于 ReqIdCollection
。请注意,删除关联并非免费操作,并且包含已处理请求的集合仍然可以被后续对 wait_response/3
、check_response/3
和 receive_response/3
的调用使用。
但是,如果不删除已处理的关联,则上述调用将无法检测到何时没有更多未完成的请求需要处理,因此您必须以其他方式跟踪此情况,而不是依赖于 no_request
返回值。请注意,如果您将仅包含已处理或放弃请求的关联的集合传递给此函数,它将始终阻塞直到 WaitTime
过期,然后返回 timeout
。
返回事件管理器中的所有事件处理程序。
此函数返回事件管理器 EventMgrRef
中安装的所有事件处理程序的列表。
有关 Handler
的描述,请参见 add_handler/3
。