gen_server call timeout

The gen_server call of Erlang has a timeout by default, if it is not returned within the specified timeout. Will exit (timeout).

gen_server call


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]),

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

When should a timeout be caught?

Obviously, if you wait a while and don’t receive a message, there are two possibilities.

  1. The opposite side could not return a message.
  2. The opposite end returned a message. But the caller has not received it.

Catch timeout and handle expired {Mref, Reply} returns

If a timeout exception is caught and a message is returned, the message is still sent to the caller’s PID mailbox. If it is a gen_server, the message needs to be processed (and it is recommended to ignore) in handle_info. Avoid crashes because the {Mref, Reply} message is not processed in handle_info.

Power etc.

Timeout does not mean that the call failed; it may succeed, but the request timed out. An idempotent interface design can be used to deal with timeout failures.

Appropriate timeout

A_node -5000ms> b_node -5000ms> outer_services If outer_services (uncontrolled external service) times out, it will cause both a_node and b_node calls to timeout. It is recommended that you use a small timeout for external use on b_node. Avoid external timeouts that cause timeout errors throughout the call chain.