【问题标题】:Ensuring an event is handled while switching gen_event handlers in Erlang/OTP确保在 Erlang/OTP 中切换 gen_event 处理程序时处理事件
【发布时间】:2011-04-15 15:18:28
【问题描述】:

假设我有多个版本的 gen_event 处理程序,并且想在程序运行时更改它们:

-module(logger_all).
-behaviour(gen_event).
-export([init/1, handle_event/2, terminate/2]).
init(_Args) ->
    {ok, []}.
handle_event({Severity, ErrorMsg}, State) ->
    io:format("***~p*** ~p~n", [Severity, ErrorMsg]),
    {ok, State}.
terminate(_Args, _State) ->
    ok.

-module(logger_errors_only).
-behaviour(gen_event).
-export([init/1, handle_event/2, terminate/2]).
init(_Args) ->
    {ok, []}.
handle_event({error, ErrorMsg}, State) ->
    io:format("***Error*** ~p~n", [ErrorMsg]),
    {ok, State}.
handle_event({_, ErrorMsg}, State) ->
    {ok, State}. %% ignore everything except errors
terminate(_Args, _State) ->
    ok.

显然,我可以通过删除一个处理程序并添加另一个处理程序来切换它们:

log_errors_only() -> 
    gen_event:delete_handler(error_man, logger_all, []),
    gen_event:add_handler(error_man, logger_errors_only, []).

但这留下了竞争条件的可能性;如果error_man 在错误的时间接收到一个事件,它不会被记录。或者如果我更改操作的顺序,它将被记录两次,这也是不可取的。如何确保它被精确处理一次?

对于这种情况,我可以只拥有一个处理程序并将日志记录级别保持为State,但假设这是不可接受的。

【问题讨论】:

    标签: events erlang erlang-otp


    【解决方案1】:

    OTP 团队擅长预见此类需求; gen_event 有一个函数可以原子地swap event handlers

    log_errors_only() ->
        gen_event:swap_handler(error_man,
                               {logger_all, swapped_out},
                               {logger_errors_only, []}).
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-20
      • 1970-01-01
      • 2018-01-25
      相关资源
      最近更新 更多