Skip to content

Commit c2e8b48

Browse files
authored
examples: expand timeout scenarios (#245)
## Summary - Expand the timeout example into a client -> forward server -> backend server call chain. - Add generated public Chat proto stubs for the timeout flow. - Document full-link timeout scenarios without relying on internal services. ## Tests - `go test ./features/timeout/... -count=1` from `examples/` - `go test ./... -count=1` from `examples/` - `git diff --check main...HEAD` - Scanned changed files for internal-only links and local paths
1 parent 42ac657 commit c2e8b48

10 files changed

Lines changed: 571 additions & 175 deletions

File tree

examples/features/timeout/README.md

Lines changed: 83 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,94 @@
11
# Timeout
2+
23
The following are some brief introductions and usage examples of trpc-go timeout feature. You can understand how the timeout mechanism of trpc-go works from these examples.
4+
35
## Usage
6+
47
Steps to use the feature. Typically:
8+
59
* start the server
6-
```
10+
11+
```shell
712
cd server && go build -v && ./server
813
```
914

10-
* start the client
15+
* open another terminal, and start the forward server
16+
1117

12-
open another terminal.
18+
```shell
19+
cd forwardserver && go build -v && ./forwardserver
1320
```
21+
22+
23+
* open another terminal, start the client
24+
25+
26+
```shell
1427
cd client && go build -v && ./client
1528
```
16-
In the demo, there are two RPC calls, SayHello and SayHi.
17-
You have set different client timeout values for the TestSayHello and TestSayHi interfaces. The client timeout value for TestSayHi is 1000ms.
18-
19-
```go
20-
opts := []client.Option{
21-
client.WithTarget(addr),
22-
client.WithTimeout(time.Millisecond * 1000),
23-
}
24-
````
25-
26-
The TestSayHello interface will call the SayHi RPC. You have set the timeout value for this call to 2000ms.
27-
```go
28-
opts := []client.Option{
29-
client.WithTarget(addr),
30-
client.WithTimeout(time.Millisecond * 2000),
31-
}
32-
```
3329

34-
In the SayHi method of the server, you have set a sleep time of 1100ms for the thread.
30+
The above example shows the "ForwardServer Full-Link Timeout".
31+
For more timeout scenarios, see the table in the next section.
32+
You can modify the timeout configuration to simulate other timeout scenarios.
33+
34+
35+
## Timeout Scenarios Explanation
36+
37+
### Call Chain
3538
```
36-
time.Sleep(time.Millisecond * 1100ms)
39+
Client -> ForwardServer -> Server
3740
```
3841

39-
When executing `./client`, you found that the TestSayHi interface timed out, while the TestSayHello interface returned normally.
4042

43+
| Timeout Scenario | Client Timeout | ForwardServer Timeout | ForwardServer Sleep | ForwardServer→Server Timeout | Server Timeout | Server Sleep | ForwardServer Error | Client Error |
44+
|:----------------|:--------------:|:--------------------:|:------------------:|:---------------------------:|:--------------:|:------------:|:-------------------|:-------------|
45+
| No Timeout | 4 | 5 | 1 | 3 | 2 | 1 | nil | nil |
46+
| Silent Server Timeout | 4 | 5 | 1 | 3 | 1 | 2 | nil | nil |
47+
| ForwardServer Normal Timeout | 4 | 2 | 3 | 3 | 2 | 1 | RetClientFullLinkTimeout | RetServerTimeout |
48+
| Client Full-Link Timeout | 3 | 5 | 4 | 3 | 2 | 1 | RetClientFullLinkTimeout | RetClientFullLinkTimeout |
49+
| ForwardServer→Server Client Timeout | 4 | 5 | 1 | 1 | 3 | 2 | RetClientTimeout | RetClientTimeout |
50+
| ForwardServer Full-Link Timeout | 4 | 5 | 6 | 3 | 2 | 1 | RetClientTimeout | RetClientFullLinkTimeout |
51+
52+
1. **Normal Case (No Timeout)**
53+
- All services complete within their timeout limits
54+
- All timeouts: Client(4s) -> ForwardServer(5s) -> Server(2s)
55+
- No errors returned
56+
57+
2. **Silent Server Timeout**
58+
- Server sleeps(2s) longer than its timeout(1s)
59+
- But since Server doesn't actively handle timeout, no error is propagated
60+
- Both Client and ForwardServer remain unaware of the timeout
61+
62+
3. **Client Full-Link Timeout**
63+
- Client timeout(3s) < ForwardServer processing time(4s)
64+
- Results in full-link timeout propagation
65+
- Both services receive RetClientFullLinkTimeout
4166

42-
## timeout mechanism in trpc-go
67+
4. **ForwardServer->Server Client Timeout**
68+
- ForwardServer->Server timeout(1s) < Server processing time(2s)
69+
- Results in simple client timeout
70+
- Both receive RetClientTimeout
71+
72+
5. **ForwardServer Normal Timeout**
73+
- ForwardServer timeout(2s) < processing time(3s)
74+
- Client receives RetServerTimeout
75+
- ForwardServer receives RetClientFullLinkTimeout
76+
77+
6. **ForwardServer Full-Link Timeout**
78+
- ForwardServer processing time(6s) exceeds all timeouts
79+
- ForwardServer detects timeout but doesn't send response as Client already abandoned request
80+
- ForwardServer reports RetServerFullLinkTimeout to monitoring system
81+
- Results in RetClientTimeout and RetClientFullLinkTimeout
82+
83+
84+
### Note
85+
All times are in seconds, and errors indicate where in the chain the timeout occurred and how it propagated through the system.
86+
87+
## timeout mechanism in trpc-go
4388

4489
The timeout mechanism of trpc-go is as follows:
4590

46-
```
91+
```raw
4792
+------------------+-----------------------+
4893
| server B | single timeout |
4994
| | +------------> |
@@ -74,16 +119,15 @@ The timeout mechanism of trpc-go is as follows:
74119
75120
```
76121

122+
* Client configuration
77123

78-
- Client configuration
79-
80-
- The total timeout time of the downstream link
124+
* The total timeout time of the downstream link
81125

82126
When the client initiates a request, it needs to specify the timeout period reserved for the downstream in the business agreement. After the timeout period is exceeded, the request will be canceled to avoid invalid waiting.
83-
127+
84128
The total timeout time of the downstream link is configured as follows, timeout: 1000 means that the maximum processing time of all backend requests invoked by the client is 1000ms
85-
86-
```
129+
130+
```yaml
87131
client: # Backend configuration for client calls.
88132
timeout: 1000 # The total timeout time of the downstream link, the longest request processing time for all backends.
89133
namespace: development # Environments for all backends.
@@ -95,21 +139,18 @@ The timeout mechanism of trpc-go is as follows:
95139
timeout: 800 # Maximum request processing time.
96140
```
97141
98-
- Single service timeout
99-
142+
* Single service timeout
143+
100144
The client may request multiple backend services at the same time. You can set the timeout period of the client call for each backend service separately. For example, the timeout: 800 configured under service above means that the timeout period for a single backend service is 800ms
101-
102-
- server configuration
145+
146+
* server configuration
103147
104148
A server can provide one or more service services, and supports setting the timeout period for each service. As follows, timeout: 1000 means that the server processing time of trpc.test.helloworld.Greeter service is up to 1000ms, and if it exceeds 1000ms, it will return a timeout.
105-
106-
```
149+
150+
```yaml
107151
server: # server configuration.
108152
app: test # Business application name.
109153
server: Greeter # process service name.
110-
bin_path: /usr/local/trpc/bin/ # The path where the binary executable and framework configuration files are located.
111-
conf_path: /usr/local/trpc/conf/ # The path where the business configuration file is located.
112-
data_path: /usr/local/trpc/data/ # The path where the business data file is located.
113154
service: # The service provided by the business service can have multiple.
114155
- name: trpc.test.helloworld.Greeter # service route name.
115156
ip: 127.0.0.1 # The service listens to the ip address. You can use the placeholder ${ip}, choose one of ip and nic, and give priority to ip.
@@ -119,13 +160,9 @@ The timeout mechanism of trpc-go is as follows:
119160
timeout: 1000 # Request maximum processing time unit milliseconds.
120161
idletime: 300000 # Connection idle time unit milliseconds.
121162
```
122-
123-
- specified in the code
163+
164+
* specified in the code
124165
125166
It supports setting the timeout period in the code. In this example, the client timeout period is set to 1000ms through the `client.WithTimeout(time.Millisecond * 1000)` method.
126167

127168
It is worth noting that the priority of code specification > the configuration file, set the timeout in the configuration file and the code at the same time, and finally adopt the configuration of the code specification, that is, the configuration takes precedence.
128-
129-
130-
131-

examples/features/timeout/client/main.go

Lines changed: 14 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -16,62 +16,28 @@ package main
1616

1717
import (
1818
"context"
19-
"fmt"
2019
"time"
2120

21+
"trpc.group/trpc-go/trpc-go"
2222
"trpc.group/trpc-go/trpc-go/client"
23-
"trpc.group/trpc-go/trpc-go/examples/features/timeout/shared"
24-
pb "trpc.group/trpc-go/trpc-go/testdata/trpc/helloworld"
23+
pb "trpc.group/trpc-go/trpc-go/examples/features/timeout/proto/chat"
24+
"trpc.group/trpc-go/trpc-go/log"
2525
)
2626

2727
func main() {
28-
fmt.Println("== testSayHello begin ==")
29-
testSayHello()
30-
fmt.Println("== testSayHello end ==")
31-
32-
fmt.Println("== testSayHi begin ==")
33-
testSayHi()
34-
fmt.Println("== testSayHi end ==")
28+
sayHi(4 * time.Second)
3529
}
3630

37-
// testSayHello is the test cases for SayHello method.
38-
func testSayHello() {
39-
ctx, cancel := context.WithTimeout(context.TODO(), time.Millisecond*2000)
31+
func sayHi(timeout time.Duration) {
32+
ctx, cancel := context.WithTimeout(trpc.BackgroundContext(), timeout)
4033
defer cancel()
41-
42-
opts := []client.Option{
43-
client.WithTarget(shared.Addr),
44-
// Setting the timeout value for this call to 2000ms.
45-
client.WithTimeout(time.Millisecond * 2000),
46-
}
47-
48-
clientProxy := pb.NewGreeterClientProxy(opts...)
49-
50-
req := &pb.HelloRequest{
51-
Msg: "trpc-go-client",
52-
}
53-
rsp, err := clientProxy.SayHello(ctx, req)
54-
fmt.Println(rsp, err)
55-
}
56-
57-
// testSayHi is the test cases for method.
58-
func testSayHi() {
59-
ctx, cancel := context.WithTimeout(context.TODO(), time.Millisecond*2000)
60-
defer cancel()
61-
62-
opts := []client.Option{
63-
client.WithTarget(shared.Addr),
64-
// Setting the timeout value for this call to 1000ms.
65-
client.WithTimeout(time.Millisecond * 1000),
66-
}
67-
68-
clientProxy := pb.NewGreeterClientProxy(opts...)
69-
70-
req := &pb.HelloRequest{
71-
Msg: "trpc-go-client",
34+
c := pb.NewChatClientProxy(client.WithTarget("ip://127.0.0.1:8001"), client.WithTimeout(timeout))
35+
rsp, err := c.UnarySayHi(ctx, &pb.SayHiRequest{
36+
Message: "trpc-go-client",
37+
})
38+
if err != nil {
39+
log.Error(err)
40+
} else {
41+
log.Info("rsp message: %s", rsp.Message)
7242
}
73-
// This rpc calling would timeout.
74-
rsp, err := clientProxy.SayHi(ctx, req)
75-
// Would print timeout error.
76-
fmt.Println(rsp, err)
7743
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//
2+
//
3+
// Tencent is pleased to support the open source community by making tRPC available.
4+
//
5+
// Copyright (C) 2023 Tencent.
6+
// All rights reserved.
7+
//
8+
// If you have downloaded a copy of the tRPC source code from Tencent,
9+
// please note that tRPC source code is licensed under the Apache 2.0 License,
10+
// A copy of the Apache 2.0 License is included in this file.
11+
//
12+
//
13+
14+
// Package main is the main package.
15+
package main
16+
17+
import (
18+
"context"
19+
"time"
20+
21+
"trpc.group/trpc-go/trpc-go"
22+
pb "trpc.group/trpc-go/trpc-go/examples/features/timeout/proto/chat"
23+
"trpc.group/trpc-go/trpc-go/log"
24+
)
25+
26+
//go:generate trpc create -p ../proto/chat/chat.proto --api-version 2 --rpconly -o ../proto/chat --protodir .. --mock=false --nogomod
27+
28+
func main() {
29+
s := trpc.NewServer()
30+
pb.RegisterChatService(s.Service("trpc.examples.timeout.forward-chat"), &chat{
31+
client: pb.NewChatClientProxy(),
32+
})
33+
if err := s.Serve(); err != nil {
34+
log.Error(err)
35+
}
36+
}
37+
38+
// timeoutServerImpl implements service.
39+
type chat struct {
40+
client pb.ChatClientProxy
41+
}
42+
43+
func (c *chat) UnarySayHi(ctx context.Context, req *pb.SayHiRequest) (*pb.SayHiResponse, error) {
44+
time.Sleep(6 * time.Second)
45+
rsp, err := c.client.UnarySayHi(ctx, req)
46+
if err != nil {
47+
log.Error(err)
48+
return nil, err
49+
}
50+
return &pb.SayHiResponse{Message: "SayHi: " + rsp.Message}, nil
51+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
global: # global config.
2+
namespace: Development # environment type, two types: production and development.
3+
env_name: test # environment name, names of multiple environments in informal settings.
4+
5+
server: # server configuration.
6+
app: examples # business application name.
7+
server: timeout # service process name.
8+
service: # business service configuration, can have multiple.
9+
- name: trpc.examples.timeout.forward-chat # the route name of the service.
10+
ip: 127.0.0.1 # the service listening ip address, can use the placeholder ${ip}, choose one of ip and nic, priority ip.
11+
port: 8001 # the service listening port, can use the placeholder ${port}.
12+
network: tcp # the service listening network type, tcp or udp.
13+
protocol: trpc # application layer protocol, trpc or http.
14+
timeout: 5000 # maximum request processing time in milliseconds.
15+
client:
16+
service:
17+
- name: trpc.examples.timeout.chat
18+
callee: trpc.examples.chat.Chat
19+
target: ip://127.0.0.1:8002
20+
timeout: 3000
21+
network: tcp
22+
protocol: trpc

0 commit comments

Comments
 (0)