檢視原始碼 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}
- 事件管理器會使用global:register_name/2
在全域註冊為GlobalName
。 如果未提供名稱,則不會註冊事件管理器。{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
。時間單位為 毫秒
。目前有效的數值為:
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}
,則會使用Handler2
取代事件處理器,方法是先呼叫Module:terminate(Args1, NewState)
,然後呼叫Module2:init({Args2, Term})
,其中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
是以下之一:- 如果事件處理器是因為呼叫
delete_handler/3
而被移除,或是回呼函式傳回remove_handler
(請參閱下方),則為normal
。 - 如果事件處理器是因為事件管理器正在終止而被移除,則為
shutdown
。 - 如果程序
Pid
透過呼叫swap_handler/3
或swap_sup_handler/3
,以另一個事件處理器NewHandler
取代了事件處理器,則為{swapped, NewHandler, Pid}
。 - 如果事件處理器是因為錯誤而被移除,則為其他
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
會在 將請求識別碼儲存在集合中,或使用 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
,則在產生的 NewReqIdCollection
中,與 Label
的關聯會從 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
,則在產生的 NewReqIdCollection
中,與 Label
的關聯會從 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
。