English | 中文
When making RPC requests, the framework sets a timeout for waiting for the response. If the specified time is exceeded, the client call will immediately return a timeout failure.
Timeouts are divided into three configurations to provide finer-grained control over timeouts:
-
Fulllink Timeout
: Upstream callers specify the maximum allowed time for the entire request through protocol fields. This means that the upstream caller requests that the response be delivered within a specific time frame. Any response received after this time is considered meaningless. This is illustrated in the diagram below, where A calls B with aFulllink Timeout
. -
Message Timeout
: This is the maximum timeout a current service is configured to spend processing a request from receiving the request message to sending the response data. This is a mechanism for the current service to control its resource utilization. It's depicted as theMessage Timeout
within service B in the diagram. -
Calling Timeout
: This is the maximum timeout for each RPC request when calling downstream services. For example, in the diagram, when B calls C, it sets aCalling Timeout
. Typically, a server may involves multiple consecutive RPC calls, as shown when B calls C and then sequentially calls D and E. TheCalling Timeout
controls the timeout for each individual RPC call.
When making an RPC call, framework will calculate the actual timeout for that specific call. The actual timeout is the minimum of the three timeout configurations mentioned above. The calculation process is as follows:
-
First, calculate the minimum of the
Fulllink Timeout
andMessage Timeout
. For example, if theFulllink Timeout
is 2 seconds and theMessage Timeout
is 1 second, then themaximum allowed processing time for the current message
is 1 second. -
When making an RPC call, calculate the minimum of the
maximum allowed processing time for the current message
and theCalling Timeout
for that specific call. For example, if B->C sets aCalling Timeout
of 5 seconds, then the actual timeout for B calling C is still 1 second. If B->C sets aCalling Timeout
of 500 milliseconds, then the actual timeout for B calling C is 500 milliseconds. In this case, the value of 500 milliseconds is also passed to C via protocol fields, and from C's perspective, it becomes itsFulllink Timeout
. TheFulllink Timeout
time is passed down the entire RPC call chain, gradually decreasing until it reaches 0, preventing the possibility of infinite loops in calls. -
Since each RPC call consumes some time, the
maximum allowed processing time for the current message
needs to be continuously updated in real-time to account for the remaining time. For example, if B calling C actually takes 200 milliseconds, then themaximum allowed processing time for the current message
is reduced to 800 milliseconds. When making B->D call, it's necessary to calculate the minimum of themaximum allowed processing time for the current message
and theCalling Timeout
for B->D. For example, if B->D sets aCalling Timeout
of 1 second, the effective timeout for this call is still 800 milliseconds.
tRPC-Go's timeout control is implemented using the Context
.
Context
is the first parameter for all RPC interfaces, allowing you to set timeouts and cancellations. Therefore, to make timeout control effective, all RPC calls must carry the Context
of the request entry. It's important to note that timeouts can only be controlled through the Context
.
Context
can only control the timeout of each individual call and cannot control the termination of goroutines. If your business code blocks without considering the Context
(e.g., using time.Sleep
), timeout control won't be effective, and the goroutine will be blocked indefinitely.
When the Server receives a request, it calculates the maximum allowed processing time for the current message
, sets a timeout using context.WithTimeout
, and cancels the current Context
when the business processing function is complete. Therefore, if you create goroutines to execute asynchronous logic, you must not use the entry request's Context
. Instead, use a new Context
such as trpc.BackgroundContext()
.
tRPC-Go's timeout control is specified entirely through configuration files.
Note: The following settings are all specific to the current service's timeout configuration, which corresponds to server B in the preceding diagram.
By default, timeouts are passed down from the source service through protocol fields, and you can configure whether to inherit them or not. Fulllink Timeout
is determined by the upstream client caller, and trpc Client by default sets the actual RPC timeout to the Fulllink Timeout
.
server:
service:
- name: trpc.app.server.service
disable_request_timeout: true # Default is false, which means the timeout inherits from the upstream service. Set to true to disable inheriting timeout values passed from the upstream service.
If you wish to completely disable timeouts, you can configure this value.
Each service can configure the maximum message processing timeout for all incoming requests when starting up.
If your business code blocks without considering the Context
(e.g., using time.Sleep
), timeout control won't be effective, and the processing goroutine won't terminate immediately.
server:
service:
- name: trpc.app.server.service
timeout: 1000 # In milliseconds, each incoming request allows a maximum execution time of 1000ms. Be mindful of distributing timeout times for all serial RPC calls within the current request. Default is 0, indicating no timeout is set.
Each RPC call can configure the maximum timeout for the current request. If your code sets the WithTimeout
option, the code configuration takes precedence. However, for flexibility, it's recommended to specify the calling timeout directly through the configuration file.
client:
service:
- name: trpc.app.server.service # Downstream service name
timeout: 500 # In milliseconds, each initiated request allows a maximum timeout of 500ms. Default is 0, indicating no timeout is set, meaning it will wait indefinitely.