2010-12-07 13 views
1

グローバルに登録されたプロセスにメッセージを送信する必要があります。そのプロセスは、バックアッププロセス(フェイルオーバー)に置き換えられてから短期間は利用できない可能性があります。メッセージを再送信するのに適していますか?

次は良い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:を追加しました指数バックオフ

+2

サイドノート:ブール値の代わりにデクリメントする整数パラメータ 'NumRetriesToGo'を渡す必要があります。 「再試行」は混乱します。最初は逆の意味があると思いました。「これは再試行です。 –

答えて

9

global:sendには2つの異なる呼び出し、try ... catch内部1、他ではないことを確認します。 ...そうではない、ちょうどそれをすることはできません。

+0

私は実際にあなたが提案したようにsend_messageの2つのバージョンを持っています。そして、あなたはブール値の代わりに整数を指すといいと思います。 – Max

+0

私はちょうどあなたのコードをもっと勉強しました。私は賢明にcase文とraise()呼び出しを避けています。優秀、ありがとう。 – Max

+0

@Max:ようこそ。ダニのためにありがとう。 –

1

私の代わりに

erlang:error({badarg,{To,Message}}) 

を行うだろう。実際の違いはありませんが、スタックトレースも生成されますが、より明確です。より汎用的な使い方と、スタックトレースを使用したい場合はerlang:raise/3が良いでしょう。

+0

私はMarceloのコードがはるかにエレガントであると思うので、直接投げられるので、例外を再スローすることについて心配する必要はありません。しかし、あなたの提案をありがとう、私はそれを念頭に置くでしょう。 – Max

関連する問題