ein Ereignis, sichergestellt wird, behandelt, während gen_event Handler in Erlang / OTP Schalt
Frage
Lassen Sie uns sagen, ich habe mehrere Versionen eines gen_event
Handler und wollen, dass sie um ändern, während das Programm ausgeführt wird:
-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.
Natürlich, ich kann sie durch Entfernen eines Handler und das Hinzufügen von den anderen wechseln um:
log_errors_only() ->
gen_event:delete_handler(error_man, logger_all, []),
gen_event:add_handler(error_man, logger_errors_only, []).
Aber diese Blätter die Möglichkeit einer Race-Bedingung; wenn error_man
ein Ereignis nur zur falschen Zeit empfängt, wird es nicht protokolliert. Oder wenn ich die Reihenfolge der Aktionen ändert, wird es zweimal protokolliert werden, was ebenfalls unerwünscht ist. Wie kann ich sicherstellen, dass es gerade einmal behandelt wird?
Für diesen Fall kann ich nur einen Handler habe und halte Ebene als State
anmelden, aber nehme an, dies ist nicht akzeptabel.
Lösung
Das OTP-Team ist gut Bedürfnisse wie diese forseeing; gen_event hat eine Funktion zum Swap-Event-Handler atomar:
log_errors_only() ->
gen_event:swap_handler(error_man,
{logger_all, swapped_out},
{logger_errors_only, []}).