談談erlang的timeout.

gen_server call timeout

erlang的gen_server call默認有超時, 若在指定的超時內沒有收到返回. 則會exit(timeout).node

gen_server call

gen.erl:160async

do_call(Process, Label, Request, Timeout) when is_atom(Process) =:= false ->
    Mref = erlang:monitor(process, Process),

    %% OTP-21:
    %% Auto-connect is asynchronous. But we still use 'noconnect' to make sure
    %% we send on the monitored connection, and not trigger a new auto-connect.
    %%
    erlang:send(Process, {Label, {self(), Mref}, Request}, [noconnect]),

    receive
        {Mref, Reply} ->
            erlang:demonitor(Mref, [flush]),
            {ok, Reply};
        {'DOWN', Mref, _, _, noconnection} ->
            Node = get_node(Process),
            exit({nodedown, Node});
        {'DOWN', Mref, _, _, Reason} ->
            exit(Reason)
    after Timeout ->
            erlang:demonitor(Mref, [flush]),
            exit(timeout)
    end.

何時應該捕獲timeout?

顯然, 若是等待一段時間後, 沒有收到消息, 有兩種可能.atom

  1. 對端未能返回消息.
  2. 對端返回了消息. 但調用端還沒有收到.

catch timeout異常和處理過時的{Mref, Reply}返回

若是捕獲了timeout異常, 對方又返回了消息, 該消息仍是會發送到調用者的pid信箱中.
如果一個gen_server, 須要在handle_info中處理(建議忽略)該消息. 避免由於沒有在handle_info 中處理{Mref, Reply}消息而崩潰.設計

冪等

超時不意味着調用失敗, 可能調用成功, 只是請求超時. 能夠使用冪等接口設計應對超時失敗.code

合適的超時時間

假設有以下調用鏈.
a_node -5000ms> b_node -5000ms> outer_services
若outer_services, 即不可控的外部服務超時, 會致使a_node, b_node的call所有超時. 建議在b_node上對外使用較小的超時時間. 避免外部超時讓整條調用鏈都出現超時錯誤.server

相關文章
相關標籤/搜索