Kernel

Reference Manual

Version 7.0

Table of Contents

erpc

Module

erpc

Module Summary

Enhanced Remote Procedure Call

Since

Module erpc was introduced in OTP 23.0.

Description

This module provide services similar to Remote Procedure Calls. A remote procedure call is a method to call a function on a remote node and collect the answer. It is used for collecting information on a remote node, or for running a function with some specific side effects on the remote node.

This is an enhanced subset of the operations provided by the rpc module. Enhanced in the sense that it makes it possible to distinguish between returned value, raised exceptions, and other errors. erpc also has better performance and scalability than the original rpc implementation. However, current rpc module will utilize erpc in order to also provide these properties when possible.

In order for an erpc operation to succeed, the remote node also needs to support erpc. Typically only ordinary Erlang nodes as of OTP 23 have erpc support.

Data Types

An opaque type of call request identifiers. For more information see send_request/4.

Exports

call(Node, Module, Function, Args) -> Result
OTP 23.0
call(Node, Module, Function, Args, Timeout) -> Result
OTP 23.0

Types

Node = node()
Module = Function = atom()
Args = [term()]
Timeout = 0..4294967295 | infinity
Result = term()

Evaluates apply(Module, Function, Args) on node Node and returns the corresponding value Result. Timeout is an integer representing the timeout in milliseconds or the atom infinity.

The call erpc:call(Node, Module, Function, Args) is equivalent to the call erpc:call(Node, Module, Function, Args, infinity)

The call() function only returns if the applied function successfully returned without raising any uncaught exceptions, the operation did not time out, and no failures occurred. In all other cases an exception is raised. The following exceptions, listed by exception class, can currently be raised by erpc:call():

throw

The applied function called throw(Value) and did not catch this exception. The exception reason Value equals the argument passed to throw/1.

exit

Exception reason:

{exception, ExitReason}

The applied function called exit(ExitReason) and did not catch this exception. The exit reason ExitReason equals the argument passed to exit/1.

{signal, ExitReason}

The process that applied the function received an exit signal and terminated due to this signal. The process terminated with exit reason ExitReason.

error

Exception reason:

{exception, ErrorReason, StackTrace}

A runtime error occurred which raised and error exception while applying the function, and the applied function did not catch the exception. The error reason ErrorReason indicates the type of error that occurred. StackTrace is formatted as when caught in a try/catch construct. The StackTrace is limited to the applied function and functions called by it.

{erpc, ERpcErrorReason}

The erpc operation failed. The following ERpcErrorReasons are the most common ones:

badarg

If any one of these are true:

  • Node is not a valid node name atom.

  • Module is not an atom.

  • Function is not an atom.

  • Args is not a proper list of terms.

  • Timeout is not the atom infinity or an integer in valid range.

noconnection

The connection to Node was lost or could not be established. The function may or may not be applied.

system_limit

The erpc operation failed due to some system limit being reached. This typically due to failure to create a process on the remote node Node, but can be other things as well.

timeout

The erpc operation timed out. The function may or may not be applied.

notsup

The remote node Node does not support this erpc operation.

If the erpc operation fails, but it is unknown if the function is/will be applied (that is, a timeout or a connection loss), the caller will not receive any further information about the result if/when the applied function completes. If the applied function explicitly communicates with the calling process, such communication may, of course, reach the calling process.

Note

You cannot make any assumptions about the process that will perform the apply(). It may be the calling process itself, a server, or a freshly spawned process.

cast(Node, Module, Function, Args) -> ok
OTP 23.0

Types

Node = node()
Module = module()
Function = atom()
Args = [term()]

Evaluates apply(Module, Function, Args) on node Node. No response is delivered to the calling process. erpc:cast() returns immediately after the cast request has been sent. Any failures beside bad arguments are silently ignored.

erpc:cast/4 fails with an {erpc, badarg} error exception if:

  • Node is not a valid node name atom.

  • Module is not an atom.

  • Function is not an atom.

  • Args is not a proper list of terms.

Note

You cannot make any assumptions about the process that will perform the apply(). It may be a server, or a freshly spawned process.

check_response(Message, RequestId) ->
                  {response, Result} | no_response
OTP 23.0

Types

Message = term()
RequestId = request_id()
Result = term()

Check if a message is a response to a call request previously made by the calling process using erpc:send_request/4. RequestId should be the value returned from the previously made erpc:send_request() call, and the corresponding response should not already have been received and handled to completion by erpc:check_response(), erpc:receive_response(), or erpc:wait_response(). Message is the message to check.

If Message does not correspond to the response, the atom no_response is returned. If Message corresponds to the response, the call operation is completed and either the result is returned as {response, Result} where Result corresponds to the value returned from the applied function or an exception is raised. The exceptions that can be raised corresponds to the same exceptions as can be raised by erpc:call/4. That is, no {erpc, timeout} error exception can be raised.

If the erpc operation fails, but it is unknown if the function is/will be applied (that is, a connection loss), the caller will not receive any further information about the result if/when the applied function completes. If the applied function explicitly communicates with the calling process, such communication may, of course, reach the calling process.

multicall(Nodes, Module, Function, Args) -> Result
OTP 23.0
multicall(Nodes, Module, Function, Args, Timeout) -> Result
OTP 23.0

Types

Nodes = [atom()]
Module = Function = atom()
Args = [term()]
Timeout = 0..4294967295 | infinity
Result =
    [{ok, ReturnValue :: term()} | caught_call_exception()]
caught_call_exception() =
    {throw, Throw :: term()} |
    {exit, {exception, Reason :: term()}} |
    {error,
     {exception, Reason :: term(), StackTrace :: [stack_item()]}} |
    {exit, {signal, Reason :: term()}} |
    {error, {erpc, Reason :: term()}}

stack_item() =
    {Module :: atom(),
     Function :: atom(),
     Arity :: arity() | (Args :: [term()]),
     Location ::
         [{file, Filename :: string()} |
          {line, Line :: integer() >= 1}]}

Performs multiple call operations in parallel on multiple nodes. The result is returned as a list where the result from each node is placed at the same position as the node name is placed in Nodes. Each item in the resulting list is formatted as either:

{ok, Result}

The call operation for this specific node returned Result.

{Class, ExceptionReason}

The call operation for this specific node raised an exception of class Class with exception reason ExceptionReason. These corresponds the the exceptions that erpc:call/5 can raise.

The call erpc:multicall(Nodes, Module, Function, Args) is equivalent to the call erpc:multicall(Nodes, Module, Function, Args, infinity). These calls are also equivalent to calling my_multicall(Nodes, Module, Function, Args) if one disregards performance:

my_multicall(Nodes, Module, Function, Args) ->
  ReqIds = lists:map(fun (Node) ->
                       erpc:send_request(Node, Module, Function, Args)
                     end,
                     Nodes),
  lists:map(fun (ReqId) ->
              try
                {ok, erpc:receive_response(ReqId, infinity)}
              catch
                Class:Reason ->
                  {Class, Reason}
              end
            end,
            ReqIds).

The Timeout value in milliseconds sets an upper time limit for all call operations to complete.

If an erpc operation fails, but it is unknown if the function is/will be applied (that is, a timeout or connection loss), the caller will not receive any further information about the result if/when the applied function completes. If the applied function communicates with the calling process, such communication may, of course, reach the calling process.

receive_response(RequestId) -> Result
OTP 23.0
receive_response(RequestId, Timeout) -> Result
OTP 23.0

Types

RequestId = request_id()
Timeout = 0..4294967295 | infinity
Result = term()

Receive a response to a call request previously made by the calling process using erpc:send_request/4. RequestId should be the value returned from the previously made erpc:send_request() call, and the corresponding response should not already have been received and handled to completion by erpc:check_response(), erpc:receive_response(), or erpc:wait_response(). Timeout equals the timeout time in milliseconds or the atom infinity. The call operation is completed once the erpc:receive_response() call returns or raise an exception.

The call erpc:receive_response(RequestId) is equivalent to the call erpc:receive_response(RequestId, infinity).

A call to the function my_call(Node, Module, Function, Args, Timeout) below is equivalent to the call erpc:call(Node, Module, Function, Args, Timeout) if one disregards performance. erpc:call() can utilize a message queue optimization which removes the need to scan the whole message queue which the combination erpc:send_request()/erpc:receive_response() cannot.

my_call(Node, Module, Function, Args, Timeout) ->
  RequestId = erpc:send_request(Node, Module, Function, Args),
  erpc:receive_response(RequestId, Timeout).

If the erpc operation fails, but it is unknown if the function is/will be applied (that is, a timeout, or a connection loss), the caller will not receive any further information about the result if/when the applied function completes. If the applied function explicitly communicates with the calling process, such communication may, of course, reach the calling process.

erpc:receive_response() will return or raise exceptions the same way as erpc:call/5 does.

send_request(Node, Module, Function, Args) -> RequestId
OTP 23.0

Types

Node = node()
Module = module()
Function = atom()
Args = [term()]
RequestId = request_id()

Send an asynchronous call request to the node Node. erpc:send_request() returns a request identifier that later is to be passed as argument to either erpc:receive_response(), erpc:wait_response(), or, erpc:check_response() in order to get the response of the call request.

erpc:send_request() fails with an {erpc, badarg} error exception if:

  • Node is not a valid node name atom.

  • Module is not an atom.

  • Function is not an atom.

  • Args is not a proper list of terms.

wait_response(RequestId) -> {response, Result} | no_response
OTP 23.0
wait_response(RequestId, WaitTime) ->
                 {response, Result} | no_response
OTP 23.0

Types

RequestId = request_id()
WaitTime = 0..4294967295 | infinity
Result = term()

Wait or poll for a response message to a call request previously made by the calling process using erpc:send_request/4. RequestId should be the value returned from the previously made erpc:send_request() call, and the corresponding response should not already have been received and handled to completion by erpc:check_response(), erpc:receive_response(), or erpc:wait_response(). WaitTime equals the time to wait in milliseconds (or the atom infinity) during the wait.

The call erpc:wait_response(RequestId) is equivalent to the call erpc:wait_response(RequestId, 0). That is, poll for a response message to a call request previously made by the calling process.

If no response is received before WaitTime milliseconds, the atom no_response is returned. It is valid to continue waiting for a response as many times as needed up until a response has been received and completed by erpc:check_response(), erpc:receive_response(), or erpc:wait_response(). If a response is received, the call operation is completed and either the result is returned as {response, Result} where Result corresponds to the value returned from the applied function or an exception is raised. The exceptions that can be raised corresponds to the same exceptions as can be raised by erpc:call/4. That is, no {erpc, timeout} error exception can be raised.

If the erpc operation fails, but it is unknown if the function is/will be applied (that is, a too large wait time value, or a connection loss), the caller will not receive any further information about the result if/when the applied function completes. If the applied function explicitly communicates with the calling process, such communication may, of course, reach the calling process.