erlang supervisor best way to handle ibrowse:send

new to Erlang and just having a bit of trouble getting my head around the new paradigm!

OK, so I have this internal function within an OTP gen_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.

If I leave out the case for handling the connection failed then I get an exit signal propagated to the supervisor and it gets shut down along with the server.

What I want to happen (at least I think this is what I want to happen) is that on a connection failure I'd like to pause and then retry send_req say 10 times and at that point the supervisor can fail.

If I do something ugly like this...

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

it shuts down the server process and yes, I get to use my (try 10 times within 10 seconds) restart strategy until it fails, which is also the desired result however the return value from the server to the supervisor is 'ok' when I would really like to return {error,error_but_please_dont_fall_over_mr_supervisor}.

I strongly suspect in this scenario that I'm supposed to handle all the business stuff like retrying failed connections within 'my_func' rather than trying to get the process to stop and then having the supervisor restart it in order to try it again.

Question: what is the 'Erlang way' in this scenario ?


I'm new to erlang too.. but how about something like this?

The code is long just because of the comments. My solution (I hope I've understood correctly your question) will receive the maximum number of attempts and then do a tail-recursive call, that will stop by pattern-matching the max number of attempts with the next one. Uses timer:sleep() to pause to simplify things.

%% @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.

EDIT: If this code is in a process which is supervised, I think it's better to have a simple_one_for_one, where you can add dinamically whatever workers you need, this is to avoid delaying initialization due to timeouts (in a one_for_one the workers are started in order, and having sleep's at that point will stop the other processes from initializing).

EDIT2: Added an example shell execution:

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}

With 1s delays between each printed message.

链接地址: http://www.djcxy.com/p/6508.html

上一篇: Erlang管理员重启间隔

下一篇: erlang主管处理ibrowse的最佳方式:发送