重发邮件的好设计?

时间:2010-12-07 10:19:15

标签: erlang

我需要向全局注册的进程发送一条消息,当它被替换为备份进程(即故障转移)时,可能在短时间内不可用。

以下代码段是否为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.

Retry参数为true或false,表示如果出现问题,应重试一次该消息。如果仍然无法发送消息,我希望引发相同的异常,就像在try-catch块之外调用global:send(To,Message)一样。

我知道上面的工作,但我担心我的case块的错误部分是否是好的erlang(例如使用erlang:raise()和rlang:get_stacktrace())。

任何使代码“更好”的想法或建议?

2 个答案:

答案 0 :(得分:9)

global:send拨打两个不同的电话,一个在try ... catch内,另一个不在:

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.

编辑:添加指数后退。就像......不,不能做到。

答案 1 :(得分:1)

我愿意

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

代替。没有真正的区别,因为这也会产生堆栈跟踪,但我认为它更清晰。 erlang:raise/3更适合更通用的用法,如果你想用堆栈跟踪做事。