2012-06-20 101 views
2

新的Erlang和只是有點麻煩讓我的頭圍繞新的範式!erlang主管最好的方式來處理ibrowse:send_req conn_failed

OK,所以我有一個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. 

如果我離開了的情況下處理,然後失敗,我得到傳播到主管的退出信號的連接,它被關閉與服務器一起。

我想要發生的事情(至少我認爲這是我想要發生的事情)是,在連接失敗時,我想暫停,然後重試send_req說10次,那時管理員可能會失敗。

如果我做了什麼醜像這樣...

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

它關閉服務器進程,是的,我明白,直到它不能用我的(嘗試在10秒內10次)重啓戰略,也是期望的結果,但是當我真的想返回{error,error_but_please_dont_fall_over_mr_supervisor}時,從服務器到管理員的返回值是'ok'。

我強烈懷疑在這種情況下,我應該處理所有的業務內容,比如在'my_func'中重試失敗的連接,而不是試圖讓流程停止,然後讓管理員重新啓動它以便嘗試再次。

問題:在這種情況下,「Erlang方式」是什麼?

回答

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,在那裏你可以dinamically任何你需要的工人,增加,這是爲了避免延遲初始化由於超時(以一個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} 

對於每個印刷信息之間1S延遲。

+0

是的,我嘗試了一些類似的東西(比你的解決方案略差一些),傳遞嘗試的次數然後遞減並測試爲零。唯一的區別是我調用stop()而不是返回一個元組,停止會關閉服務器(並重新啓動它),但不會返回有用的消息,{error,too_many_retries}將返回一條有用的消息,但不會關閉服務器。 – unclejimbob

+0

我希望找到一個解決方案來獲得這兩個世界的組合,因爲send_req錯誤出現我重試了10次,然後如果它仍然失敗,我抓住它,然後再次拋出,但以避免導致監督員失敗 - 但我也認爲這不是'Erlang的方式'。我認爲你的解決方案是要走的路,因爲如果發生任何其他異常,它應該由主管的重啓戰略覆蓋。 如果其他人有不同的方法或意見,那麼一定要通過。 非常感謝 – unclejimbob

+0

@unclejimbob從我所瞭解的情況來看,只有在達到最大嘗試次數時,纔想讓監督人員失敗,對嗎?然後讓監督員重新啓動工作人員,以便從頂部重試整個操作。這是我試圖用代碼做的事情。你可能想用erlang來補充它:error(too_many_attempts)。所以,只有在達到最大嘗試或拋出未知錯誤(未捕獲)時,纔會「讓它崩潰」。我不喜歡定時器:sleep()是你的工作人員不服從sys消息,所以另一種解決方案是接收超時 – marcelog

相關問題