2

アーランは初めてで、新しいパラダイムに頭を悩ませるのに少し苦労しています!

OK、それで私はOTPgen_server内にこの内部関数を持っています:

my_func() ->
Result = ibrowse:send_req(?ROOTPAGE,[{"User-Agent",?USERAGENT}],get),
case Result of
    {ok, "200", _, Xml} -> %<<do some stuff that won't interest you>>
,ok;
{error,{conn_failed,{error,nxdomain}}} -> <<what the heck do I do here?>>
end.

接続が失敗した場合の処理​​を省略した場合、終了シグナルがスーパーバイザーに伝播され、サーバーとともにシャットダウンされます。

私がしたいこと(少なくともこれが私がしたいことだと思います)は、接続障害時に一時停止してからsend_reqを10回再試行すると、その時点でスーパーバイザーが失敗する可能性があることです。

私がこのような醜いことをしたら...

{error,{conn_failed,{error,nxdomain}}} -> stop()

サーバープロセスをシャットダウンし、はい、失敗するまで(10秒以内に10回試行)再起動戦略を使用できます。これも望ましい結果ですが、サーバーからスーパーバイザーへの戻り値は「ok」です。本当に{error、error_but_please_dont_fall_over_mr_supervisor}を返したいです。

このシナリオでは、プロセスを停止させてからスーパーバイザーに再起動させて再試行するのではなく、「my_func」内で失敗した接続を再試行するなど、すべてのビジネスを処理することになっていると強く思います。

質問:このシナリオでの「Erlangの方法」とは何ですか?

4

1 に答える 1

2

私もerlangは初めてです..しかし、このようなものはどうですか?

コメントのせいでコードが長い。私の解決策 (あなたの質問を正しく理解していることを願っています) は、最大試行回数を受け取り、末尾再帰呼び出しを実行します。これは、最大試行回数を次の試行とパターン マッチングすることによって停止します。timer:sleep() を使用して一時停止し、物事を簡素化します。

%% @doc Instead of having my_func/0, you have
%% my_func/1, so we can "inject" the max number of
%% attempts. This one will call your tail-recursive
%% one
my_func(MaxAttempts) ->
    my_func(MaxAttempts, 0).

%% @doc This one will match when the maximum number
%% of attempts have been reached, terminates the
%% tail recursion.
my_func(MaxAttempts, MaxAttempts) ->
    {error, too_many_retries};

%% @doc Here's where we do the work, by having
%% an accumulator that is incremented with each
%% failed attempt.
my_func(MaxAttempts, Counter) ->
    io:format("Attempt #~B~n", [Counter]),
    % Simulating the error here.
    Result = {error,{conn_failed,{error,nxdomain}}},
    case Result of
        {ok, "200", _, Xml} -> ok;
        {error,{conn_failed,{error,nxdomain}}} ->
            % Wait, then tail-recursive call.
            timer:sleep(1000),
            my_func(MaxAttempts, Counter + 1)
    end.

編集:このコードが監視されているプロセスにある場合、必要なワーカーを動的に追加できるsimple_one_for_oneを使用する方がよいと思います。これは、タイムアウトによる初期化の遅延を避けるためです(one_for_oneでは、ワーカーが開始されます)その時点でスリープ状態にすると、他のプロセスの初期化が停止します)。

EDIT2: シェル実行の例を追加:

1> c(my_func).
my_func.erl:26: Warning: variable 'Xml' is unused
{ok,my_func}
2> my_func:my_func(5).
Attempt #0
Attempt #1
Attempt #2
Attempt #3
Attempt #4
{error,too_many_retries}

各出力メッセージ間に 1 秒の遅延があります。

于 2012-06-20T01:24:52.063 に答える