Assurer un événement de commutation est manipulé tandis que les gestionnaires d'gen_event en Erlang / OTP
Question
Soit s dire que j'ai plusieurs versions d'un gestionnaire de gen_event
et veulent les changer autour pendant que le programme en cours d'exécution:
-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.
Evidemment, je peux les passer autour en enlevant un gestionnaire et en ajoutant l'autre:
log_errors_only() ->
gen_event:delete_handler(error_man, logger_all, []),
gen_event:add_handler(error_man, logger_errors_only, []).
Mais cela laisse une possibilité d'une condition de course; si error_man
reçoit un événement juste au mauvais moment, il ne sera pas connecté. Ou si je change l'ordre des actions, il sera enregistré deux fois, ce qui est également indésirable. Comment puis-je vous assurer qu'il est géré exactement une fois?
Dans ce cas, je peux juste avoir un gestionnaire et de garder le niveau de consignation comme State
, mais supposons que ce n'est pas acceptable.
La solution
L'équipe du Bureau du Procureur est bon à besoins Prévoyant comme celui-ci; gen_event a une fonction gestionnaires d'événements d'échange atomiquement:
log_errors_only() ->
gen_event:swap_handler(error_man,
{logger_all, swapped_out},
{logger_errors_only, []}).