Обеспечение обработки события при переключении обработчиков gen_event в Erlang / OTP - PullRequest
3 голосов
/ 22 сентября 2010

Допустим, у меня есть несколько версий обработчика 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, но предположим, что это неприемлемо.

1 Ответ

3 голосов
/ 23 сентября 2010

Команда OTP хорошо справляется с такими задачами; У gen_event есть функция поменять местами обработчики событий атомарно:

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