グローバルに登録されたプロセスにメッセージを送信する必要があります。そのプロセスは、バックアッププロセス(フェイルオーバー)に置き換えられてから短期間は利用できない可能性があります。メッセージを再送信するのに適していますか?
次は良いErlangのコードを抜粋です
% send message to globally registered process, with possibility to retry once
send_message(To, Message, Retry) ->
try global:send(To, Message)
catch
% registered process To is unavailable
exit: {badarg, {To, Message}} ->
io:format("catch: exit: {badarg,{~w, ~w}}~n", [To, Message]), % dbg only
case Retry of
true ->
% retry sending message, after 1 second
sleep(1000),
send_message(To, Message, false);
false ->
% re-throw caught exit, including stack trace
erlang:raise(exit, {badarg, {To, Message}},
erlang:get_stacktrace())
end
end.
再試行パラメータは問題があった場合、メッセージが一度再試行されるべきで示す、trueまたはfalseのいずれかです。それでもメッセージを送信できない場合は、グローバル:send(To、Message)をtry-catchブロックの外側で呼び出して、同じ例外を発生させます。
私は上記の作品を知っていますが、私のケースブロックの偽のセクションが良いerlang(erlang:raise()とrlang:get_stacktrace()など)を使用しているかどうかは懸念しています。
「良い」コードを作成するための考えや提案はありますか?
send_message(To, Message, 0, _, _) ->
global:send(To, Message);
send_message(To, Message, RetriesLeft, RetryDelayMs, MaxRetryDelayMs) ->
try
global:send(To, Message)
catch
% registered process To is unavailable
exit: {badarg, {To, Message}} ->
io:format("catch: exit: {badarg,{~w, ~w}}~n", [To, Message]), % dbg only
% retry after RetryDelayMs milliseconds
sleep(min(RetryDelayMs, MaxRetryDelayMs)),
send_message(To, Message, RetriesLeft - 1, 2 * RetryDelayMs, MaxRetryDelayMs)
end.
EDIT:を追加しました指数バックオフ
サイドノート:ブール値の代わりにデクリメントする整数パラメータ 'NumRetriesToGo'を渡す必要があります。 「再試行」は混乱します。最初は逆の意味があると思いました。「これは再試行です。 –