From 01a7f54e421927c86cd14eedfc86c02739ea3d2d Mon Sep 17 00:00:00 2001 From: junevanlong Date: Mon, 22 Jun 2026 11:28:36 +0800 Subject: [PATCH] examples: expand timeout scenarios --- examples/features/timeout/README.md | 129 ++++++---- examples/features/timeout/client/main.go | 62 ++--- .../features/timeout/forwardserver/main.go | 51 ++++ .../timeout/forwardserver/trpc_go.yaml | 22 ++ .../features/timeout/proto/chat/chat.pb.go | 232 ++++++++++++++++++ .../features/timeout/proto/chat/chat.proto | 22 ++ .../features/timeout/proto/chat/chat.trpc.go | 126 ++++++++++ examples/features/timeout/server/main.go | 42 ++-- examples/features/timeout/server/trpc_go.yaml | 42 +--- examples/features/timeout/shared/constant.go | 18 -- 10 files changed, 571 insertions(+), 175 deletions(-) create mode 100644 examples/features/timeout/forwardserver/main.go create mode 100644 examples/features/timeout/forwardserver/trpc_go.yaml create mode 100644 examples/features/timeout/proto/chat/chat.pb.go create mode 100644 examples/features/timeout/proto/chat/chat.proto create mode 100644 examples/features/timeout/proto/chat/chat.trpc.go delete mode 100644 examples/features/timeout/shared/constant.go diff --git a/examples/features/timeout/README.md b/examples/features/timeout/README.md index 82e5397d..9923000f 100644 --- a/examples/features/timeout/README.md +++ b/examples/features/timeout/README.md @@ -1,49 +1,94 @@ # Timeout + 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. + ## Usage + Steps to use the feature. Typically: + * start the server -``` + +```shell cd server && go build -v && ./server ``` -* start the client +* open another terminal, and start the forward server + - open another terminal. +```shell +cd forwardserver && go build -v && ./forwardserver ``` + + +* open another terminal, start the client + + +```shell cd client && go build -v && ./client ``` -In the demo, there are two RPC calls, SayHello and SayHi. -You have set different client timeout values for the TestSayHello and TestSayHi interfaces. The client timeout value for TestSayHi is 1000ms. - -```go -opts := []client.Option{ - client.WithTarget(addr), - client.WithTimeout(time.Millisecond * 1000), -} -```` - -The TestSayHello interface will call the SayHi RPC. You have set the timeout value for this call to 2000ms. -```go -opts := []client.Option{ - client.WithTarget(addr), - client.WithTimeout(time.Millisecond * 2000), -} -``` -In the SayHi method of the server, you have set a sleep time of 1100ms for the thread. +The above example shows the "ForwardServer Full-Link Timeout". +For more timeout scenarios, see the table in the next section. +You can modify the timeout configuration to simulate other timeout scenarios. + + +## Timeout Scenarios Explanation + +### Call Chain ``` -time.Sleep(time.Millisecond * 1100ms) +Client -> ForwardServer -> Server ``` -When executing `./client`, you found that the TestSayHi interface timed out, while the TestSayHello interface returned normally. +| Timeout Scenario | Client Timeout | ForwardServer Timeout | ForwardServer Sleep | ForwardServer→Server Timeout | Server Timeout | Server Sleep | ForwardServer Error | Client Error | +|:----------------|:--------------:|:--------------------:|:------------------:|:---------------------------:|:--------------:|:------------:|:-------------------|:-------------| +| No Timeout | 4 | 5 | 1 | 3 | 2 | 1 | nil | nil | +| Silent Server Timeout | 4 | 5 | 1 | 3 | 1 | 2 | nil | nil | +| ForwardServer Normal Timeout | 4 | 2 | 3 | 3 | 2 | 1 | RetClientFullLinkTimeout | RetServerTimeout | +| Client Full-Link Timeout | 3 | 5 | 4 | 3 | 2 | 1 | RetClientFullLinkTimeout | RetClientFullLinkTimeout | +| ForwardServer→Server Client Timeout | 4 | 5 | 1 | 1 | 3 | 2 | RetClientTimeout | RetClientTimeout | +| ForwardServer Full-Link Timeout | 4 | 5 | 6 | 3 | 2 | 1 | RetClientTimeout | RetClientFullLinkTimeout | + +1. **Normal Case (No Timeout)** + - All services complete within their timeout limits + - All timeouts: Client(4s) -> ForwardServer(5s) -> Server(2s) + - No errors returned + +2. **Silent Server Timeout** + - Server sleeps(2s) longer than its timeout(1s) + - But since Server doesn't actively handle timeout, no error is propagated + - Both Client and ForwardServer remain unaware of the timeout + +3. **Client Full-Link Timeout** + - Client timeout(3s) < ForwardServer processing time(4s) + - Results in full-link timeout propagation + - Both services receive RetClientFullLinkTimeout -## timeout mechanism in trpc-go +4. **ForwardServer->Server Client Timeout** + - ForwardServer->Server timeout(1s) < Server processing time(2s) + - Results in simple client timeout + - Both receive RetClientTimeout + +5. **ForwardServer Normal Timeout** + - ForwardServer timeout(2s) < processing time(3s) + - Client receives RetServerTimeout + - ForwardServer receives RetClientFullLinkTimeout + +6. **ForwardServer Full-Link Timeout** + - ForwardServer processing time(6s) exceeds all timeouts + - ForwardServer detects timeout but doesn't send response as Client already abandoned request + - ForwardServer reports RetServerFullLinkTimeout to monitoring system + - Results in RetClientTimeout and RetClientFullLinkTimeout + + +### Note +All times are in seconds, and errors indicate where in the chain the timeout occurred and how it propagated through the system. + +## timeout mechanism in trpc-go The timeout mechanism of trpc-go is as follows: -``` +```raw +------------------+-----------------------+ | server B | single timeout | | | +------------> | @@ -74,16 +119,15 @@ The timeout mechanism of trpc-go is as follows: ``` +* Client configuration -- Client configuration - - - The total timeout time of the downstream link + * The total timeout time of the downstream link 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. - + 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 - - ``` + + ```yaml client: # Backend configuration for client calls. timeout: 1000 # The total timeout time of the downstream link, the longest request processing time for all backends. namespace: development # Environments for all backends. @@ -95,21 +139,18 @@ The timeout mechanism of trpc-go is as follows: timeout: 800 # Maximum request processing time. ``` - - Single service timeout - + * Single service timeout + 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 - -- server configuration + +* server configuration 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. - - ``` + + ```yaml server: # server configuration. app: test # Business application name. server: Greeter # process service name. - bin_path: /usr/local/trpc/bin/ # The path where the binary executable and framework configuration files are located. - conf_path: /usr/local/trpc/conf/ # The path where the business configuration file is located. - data_path: /usr/local/trpc/data/ # The path where the business data file is located. service: # The service provided by the business service can have multiple. - name: trpc.test.helloworld.Greeter # service route name. 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: timeout: 1000 # Request maximum processing time unit milliseconds. idletime: 300000 # Connection idle time unit milliseconds. ``` - -- specified in the code + +* specified in the code 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. 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. - - - - diff --git a/examples/features/timeout/client/main.go b/examples/features/timeout/client/main.go index 9d5dbca9..1d0025ad 100644 --- a/examples/features/timeout/client/main.go +++ b/examples/features/timeout/client/main.go @@ -16,62 +16,28 @@ package main import ( "context" - "fmt" "time" + "trpc.group/trpc-go/trpc-go" "trpc.group/trpc-go/trpc-go/client" - "trpc.group/trpc-go/trpc-go/examples/features/timeout/shared" - pb "trpc.group/trpc-go/trpc-go/testdata/trpc/helloworld" + pb "trpc.group/trpc-go/trpc-go/examples/features/timeout/proto/chat" + "trpc.group/trpc-go/trpc-go/log" ) func main() { - fmt.Println("== testSayHello begin ==") - testSayHello() - fmt.Println("== testSayHello end ==") - - fmt.Println("== testSayHi begin ==") - testSayHi() - fmt.Println("== testSayHi end ==") + sayHi(4 * time.Second) } -// testSayHello is the test cases for SayHello method. -func testSayHello() { - ctx, cancel := context.WithTimeout(context.TODO(), time.Millisecond*2000) +func sayHi(timeout time.Duration) { + ctx, cancel := context.WithTimeout(trpc.BackgroundContext(), timeout) defer cancel() - - opts := []client.Option{ - client.WithTarget(shared.Addr), - // Setting the timeout value for this call to 2000ms. - client.WithTimeout(time.Millisecond * 2000), - } - - clientProxy := pb.NewGreeterClientProxy(opts...) - - req := &pb.HelloRequest{ - Msg: "trpc-go-client", - } - rsp, err := clientProxy.SayHello(ctx, req) - fmt.Println(rsp, err) -} - -// testSayHi is the test cases for method. -func testSayHi() { - ctx, cancel := context.WithTimeout(context.TODO(), time.Millisecond*2000) - defer cancel() - - opts := []client.Option{ - client.WithTarget(shared.Addr), - // Setting the timeout value for this call to 1000ms. - client.WithTimeout(time.Millisecond * 1000), - } - - clientProxy := pb.NewGreeterClientProxy(opts...) - - req := &pb.HelloRequest{ - Msg: "trpc-go-client", + c := pb.NewChatClientProxy(client.WithTarget("ip://127.0.0.1:8001"), client.WithTimeout(timeout)) + rsp, err := c.UnarySayHi(ctx, &pb.SayHiRequest{ + Message: "trpc-go-client", + }) + if err != nil { + log.Error(err) + } else { + log.Info("rsp message: %s", rsp.Message) } - // This rpc calling would timeout. - rsp, err := clientProxy.SayHi(ctx, req) - // Would print timeout error. - fmt.Println(rsp, err) } diff --git a/examples/features/timeout/forwardserver/main.go b/examples/features/timeout/forwardserver/main.go new file mode 100644 index 00000000..f1b61e0f --- /dev/null +++ b/examples/features/timeout/forwardserver/main.go @@ -0,0 +1,51 @@ +// +// +// Tencent is pleased to support the open source community by making tRPC available. +// +// Copyright (C) 2023 Tencent. +// All rights reserved. +// +// If you have downloaded a copy of the tRPC source code from Tencent, +// please note that tRPC source code is licensed under the Apache 2.0 License, +// A copy of the Apache 2.0 License is included in this file. +// +// + +// Package main is the main package. +package main + +import ( + "context" + "time" + + "trpc.group/trpc-go/trpc-go" + pb "trpc.group/trpc-go/trpc-go/examples/features/timeout/proto/chat" + "trpc.group/trpc-go/trpc-go/log" +) + +//go:generate trpc create -p ../proto/chat/chat.proto --api-version 2 --rpconly -o ../proto/chat --protodir .. --mock=false --nogomod + +func main() { + s := trpc.NewServer() + pb.RegisterChatService(s.Service("trpc.examples.timeout.forward-chat"), &chat{ + client: pb.NewChatClientProxy(), + }) + if err := s.Serve(); err != nil { + log.Error(err) + } +} + +// timeoutServerImpl implements service. +type chat struct { + client pb.ChatClientProxy +} + +func (c *chat) UnarySayHi(ctx context.Context, req *pb.SayHiRequest) (*pb.SayHiResponse, error) { + time.Sleep(6 * time.Second) + rsp, err := c.client.UnarySayHi(ctx, req) + if err != nil { + log.Error(err) + return nil, err + } + return &pb.SayHiResponse{Message: "SayHi: " + rsp.Message}, nil +} diff --git a/examples/features/timeout/forwardserver/trpc_go.yaml b/examples/features/timeout/forwardserver/trpc_go.yaml new file mode 100644 index 00000000..eafd6313 --- /dev/null +++ b/examples/features/timeout/forwardserver/trpc_go.yaml @@ -0,0 +1,22 @@ +global: # global config. + namespace: Development # environment type, two types: production and development. + env_name: test # environment name, names of multiple environments in informal settings. + +server: # server configuration. + app: examples # business application name. + server: timeout # service process name. + service: # business service configuration, can have multiple. + - name: trpc.examples.timeout.forward-chat # the route name of the service. + ip: 127.0.0.1 # the service listening ip address, can use the placeholder ${ip}, choose one of ip and nic, priority ip. + port: 8001 # the service listening port, can use the placeholder ${port}. + network: tcp # the service listening network type, tcp or udp. + protocol: trpc # application layer protocol, trpc or http. + timeout: 5000 # maximum request processing time in milliseconds. +client: + service: + - name: trpc.examples.timeout.chat + callee: trpc.examples.chat.Chat + target: ip://127.0.0.1:8002 + timeout: 3000 + network: tcp + protocol: trpc \ No newline at end of file diff --git a/examples/features/timeout/proto/chat/chat.pb.go b/examples/features/timeout/proto/chat/chat.pb.go new file mode 100644 index 00000000..beb108ed --- /dev/null +++ b/examples/features/timeout/proto/chat/chat.pb.go @@ -0,0 +1,232 @@ +// +// +// Tencent is pleased to support the open source community by making tRPC available. +// +// Copyright (C) 2023 Tencent. +// All rights reserved. +// +// If you have downloaded a copy of the tRPC source code from Tencent, +// please note that tRPC source code is licensed under the Apache 2.0 License, +// A copy of the Apache 2.0 License is included in this file. +// +// + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v7.35.0 +// source: chat.proto + +package chat + +import ( + reflect "reflect" + sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// EchoRequest is the request for say hi. +type SayHiRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *SayHiRequest) Reset() { + *x = SayHiRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SayHiRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SayHiRequest) ProtoMessage() {} + +func (x *SayHiRequest) ProtoReflect() protoreflect.Message { + mi := &file_chat_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SayHiRequest.ProtoReflect.Descriptor instead. +func (*SayHiRequest) Descriptor() ([]byte, []int) { + return file_chat_proto_rawDescGZIP(), []int{0} +} + +func (x *SayHiRequest) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +// EchoResponse is the response for say hi. +type SayHiResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *SayHiResponse) Reset() { + *x = SayHiResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SayHiResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SayHiResponse) ProtoMessage() {} + +func (x *SayHiResponse) ProtoReflect() protoreflect.Message { + mi := &file_chat_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SayHiResponse.ProtoReflect.Descriptor instead. +func (*SayHiResponse) Descriptor() ([]byte, []int) { + return file_chat_proto_rawDescGZIP(), []int{1} +} + +func (x *SayHiResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +var File_chat_proto protoreflect.FileDescriptor + +var file_chat_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x22, 0x28, 0x0a, 0x0c, 0x53, 0x61, 0x79, 0x48, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x29, 0x0a, 0x0d, 0x53, 0x61, + 0x79, 0x48, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x5b, 0x0a, 0x04, 0x43, 0x68, 0x61, 0x74, 0x12, 0x53, 0x0a, + 0x0a, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x53, 0x61, 0x79, 0x48, 0x69, 0x12, 0x20, 0x2e, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x53, 0x61, 0x79, 0x48, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, + 0x61, 0x74, 0x2e, 0x53, 0x61, 0x79, 0x48, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x42, 0x41, 0x5a, 0x3f, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x2f, 0x74, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x6f, 0x2f, 0x74, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x6f, + 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2f, 0x63, 0x68, 0x61, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_chat_proto_rawDescOnce sync.Once + file_chat_proto_rawDescData = file_chat_proto_rawDesc +) + +func file_chat_proto_rawDescGZIP() []byte { + file_chat_proto_rawDescOnce.Do(func() { + file_chat_proto_rawDescData = protoimpl.X.CompressGZIP(file_chat_proto_rawDescData) + }) + return file_chat_proto_rawDescData +} + +var file_chat_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_chat_proto_goTypes = []interface{}{ + (*SayHiRequest)(nil), // 0: trpc.examples.chat.SayHiRequest + (*SayHiResponse)(nil), // 1: trpc.examples.chat.SayHiResponse +} +var file_chat_proto_depIdxs = []int32{ + 0, // 0: trpc.examples.chat.Chat.UnarySayHi:input_type -> trpc.examples.chat.SayHiRequest + 1, // 1: trpc.examples.chat.Chat.UnarySayHi:output_type -> trpc.examples.chat.SayHiResponse + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_chat_proto_init() } +func file_chat_proto_init() { + if File_chat_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_chat_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SayHiRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SayHiResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_chat_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_chat_proto_goTypes, + DependencyIndexes: file_chat_proto_depIdxs, + MessageInfos: file_chat_proto_msgTypes, + }.Build() + File_chat_proto = out.File + file_chat_proto_rawDesc = nil + file_chat_proto_goTypes = nil + file_chat_proto_depIdxs = nil +} diff --git a/examples/features/timeout/proto/chat/chat.proto b/examples/features/timeout/proto/chat/chat.proto new file mode 100644 index 00000000..afbb5d00 --- /dev/null +++ b/examples/features/timeout/proto/chat/chat.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +package trpc.examples.chat; + +option go_package = "trpc.group/trpc-go/trpc-go/examples/features/timeout/proto/chat"; + + +// Echo is the echo service. +service Chat { + // UnarySayHi is unary say hi. + rpc UnarySayHi(SayHiRequest) returns (SayHiResponse) {} +} + +// EchoRequest is the request for say hi. +message SayHiRequest { + string message = 1; +} + +// EchoResponse is the response for say hi. +message SayHiResponse { + string message = 1; +} diff --git a/examples/features/timeout/proto/chat/chat.trpc.go b/examples/features/timeout/proto/chat/chat.trpc.go new file mode 100644 index 00000000..4e79f03e --- /dev/null +++ b/examples/features/timeout/proto/chat/chat.trpc.go @@ -0,0 +1,126 @@ +// +// +// Tencent is pleased to support the open source community by making tRPC available. +// +// Copyright (C) 2023 Tencent. +// All rights reserved. +// +// If you have downloaded a copy of the tRPC source code from Tencent, +// please note that tRPC source code is licensed under the Apache 2.0 License, +// A copy of the Apache 2.0 License is included in this file. +// +// + +// Code generated by trpc-go/trpc-go-cmdline v2.9.9. DO NOT EDIT. +// source: chat.proto + +package chat + +import ( + "context" + "errors" + "fmt" + + _ "trpc.group/trpc-go/trpc-go" + "trpc.group/trpc-go/trpc-go/client" + "trpc.group/trpc-go/trpc-go/codec" + _ "trpc.group/trpc-go/trpc-go/http" + "trpc.group/trpc-go/trpc-go/server" +) + +// START ======================================= Server Service Definition ======================================= START + +// ChatService defines service. +type ChatService interface { + // UnarySayHi UnarySayHi is unary say hi. + UnarySayHi(ctx context.Context, req *SayHiRequest) (*SayHiResponse, error) +} + +func ChatService_UnarySayHi_Handler(svr interface{}, ctx context.Context, f server.FilterFunc) (interface{}, error) { + req := &SayHiRequest{} + filters, err := f(req) + if err != nil { + return nil, err + } + handleFunc := func(ctx context.Context, reqbody interface{}) (interface{}, error) { + return svr.(ChatService).UnarySayHi(ctx, reqbody.(*SayHiRequest)) + } + + var rsp interface{} + rsp, err = filters.Filter(ctx, req, handleFunc) + if err != nil { + return nil, err + } + return rsp, nil +} + +// ChatServer_ServiceDesc descriptor for server.RegisterService. +var ChatServer_ServiceDesc = server.ServiceDesc{ + ServiceName: "trpc.examples.chat.Chat", + HandlerType: ((*ChatService)(nil)), + Methods: []server.Method{ + { + Name: "/trpc.examples.chat.Chat/UnarySayHi", + Func: ChatService_UnarySayHi_Handler, + }, + }, +} + +// RegisterChatService registers service. +func RegisterChatService(s server.Service, svr ChatService) { + if err := s.Register(&ChatServer_ServiceDesc, svr); err != nil { + panic(fmt.Sprintf("Chat register error:%v", err)) + } +} + +// START --------------------------------- Default Unimplemented Server Service --------------------------------- START + +type UnimplementedChat struct{} + +// UnarySayHi UnarySayHi is unary say hi. +func (s *UnimplementedChat) UnarySayHi(ctx context.Context, req *SayHiRequest) (*SayHiResponse, error) { + return nil, errors.New("rpc UnarySayHi of service Chat is not implemented") +} + +// END --------------------------------- Default Unimplemented Server Service --------------------------------- END + +// END ======================================= Server Service Definition ======================================= END + +// START ======================================= Client Service Definition ======================================= START + +// ChatClientProxy defines service client proxy +type ChatClientProxy interface { + // UnarySayHi UnarySayHi is unary say hi. + UnarySayHi(ctx context.Context, req *SayHiRequest, opts ...client.Option) (rsp *SayHiResponse, err error) +} + +type ChatClientProxyImpl struct { + client client.Client + opts []client.Option +} + +var NewChatClientProxy = func(opts ...client.Option) ChatClientProxy { + return &ChatClientProxyImpl{client: client.DefaultClient, opts: opts} +} + +func (c *ChatClientProxyImpl) UnarySayHi(ctx context.Context, req *SayHiRequest, opts ...client.Option) (*SayHiResponse, error) { + ctx, msg := codec.WithCloneMessage(ctx) + defer codec.PutBackMessage(msg) + msg.WithClientRPCName("/trpc.examples.chat.Chat/UnarySayHi") + msg.WithCalleeServiceName(ChatServer_ServiceDesc.ServiceName) + msg.WithCalleeApp("examples") + msg.WithCalleeServer("chat") + msg.WithCalleeService("Chat") + msg.WithCalleeMethod("UnarySayHi") + msg.WithSerializationType(codec.SerializationTypePB) + callopts := make([]client.Option, 0, len(c.opts)+len(opts)) + callopts = append(callopts, c.opts...) + callopts = append(callopts, opts...) + rsp := &SayHiResponse{} + if err := c.client.Invoke(ctx, req, rsp, callopts...); err != nil { + return nil, err + } + return rsp, nil +} + +// END ======================================= Client Service Definition ======================================= END diff --git a/examples/features/timeout/server/main.go b/examples/features/timeout/server/main.go index 73f1da60..3054f917 100644 --- a/examples/features/timeout/server/main.go +++ b/examples/features/timeout/server/main.go @@ -18,42 +18,30 @@ import ( "context" "time" - trpc "trpc.group/trpc-go/trpc-go" + "trpc.group/trpc-go/trpc-go" "trpc.group/trpc-go/trpc-go/client" - "trpc.group/trpc-go/trpc-go/examples/features/timeout/shared" + pb "trpc.group/trpc-go/trpc-go/examples/features/timeout/proto/chat" "trpc.group/trpc-go/trpc-go/log" - pb "trpc.group/trpc-go/trpc-go/testdata/trpc/helloworld" ) +//go:generate trpc create -p ../proto/chat/chat.proto --api-version 2 --rpconly -o ../proto/chat --protodir .. --mock=false --nogomod + func main() { s := trpc.NewServer() - pb.RegisterGreeterService(s, &timeoutServerImpl{}) - s.Serve() + pb.RegisterChatService(s.Service("trpc.examples.timeout.chat"), &chat{ + client: pb.NewChatClientProxy(client.WithTarget("ip://127.0.0.1:8002")), + }) + if err := s.Serve(); err != nil { + log.Error(err) + } } // timeoutServerImpl implements service. -type timeoutServerImpl struct{} - -// SayHello implements `SayHello` method. -func (t *timeoutServerImpl) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) { - rsp := &pb.HelloReply{} - log.Debugf("timeoutServerImpl SayHello recv req:%s", req) - proxy := pb.NewGreeterClientProxy() - hi, err := proxy.SayHi(ctx, req, client.WithTarget(shared.Addr)) - if err != nil { - log.Errorf("call SayHi fail:%v", err) - return nil, err - } - rsp.Msg = "SayHello: " + hi.Msg - return rsp, nil +type chat struct { + client pb.ChatClientProxy } -// SayHi implements `SayHello` method. -func (t *timeoutServerImpl) SayHi(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) { - rsp := &pb.HelloReply{} - log.Debugf("timeoutServerImpl SayHi recv req:%s", req) - time.Sleep(time.Millisecond * 1100) - rsp.Msg = "SayHi: " + req.Msg - - return rsp, nil +func (c *chat) UnarySayHi(ctx context.Context, req *pb.SayHiRequest) (*pb.SayHiResponse, error) { + time.Sleep(1 * time.Second) + return &pb.SayHiResponse{Message: "SayHi: " + req.Message}, nil } diff --git a/examples/features/timeout/server/trpc_go.yaml b/examples/features/timeout/server/trpc_go.yaml index 069d938f..8b0579c3 100644 --- a/examples/features/timeout/server/trpc_go.yaml +++ b/examples/features/timeout/server/trpc_go.yaml @@ -3,42 +3,12 @@ global: # global config. env_name: test # environment name, names of multiple environments in informal settings. server: # server configuration. - app: test # business application name. - server: helloworld # service process name. - bin_path: /usr/local/trpc/bin/ # paths to binary executables and framework configuration files. - conf_path: /usr/local/trpc/conf/ # paths to business configuration files. - data_path: /usr/local/trpc/data/ # paths to business data files. - service: # business service configuration,can have multiple. - - name: trpc.test.helloworld.Greeter # the route name of the service. + app: examples # business application name. + server: timeout # service process name. + service: # business service configuration, can have multiple. + - name: trpc.examples.timeout.chat # the route name of the service. ip: 127.0.0.1 # the service listening ip address, can use the placeholder ${ip}, choose one of ip and nic, priority ip. - port: 8000 # the service listening port, can use the placeholder ${port}. + port: 8002 # the service listening port, can use the placeholder ${port}. network: tcp # the service listening network type, tcp or udp. protocol: trpc # application layer protocol, trpc or http. - # timeout: 1000 # maximum request processing time in milliseconds. - idletime: 300000 # connection idle time in milliseconds. - -client: # configuration for client calls. - # timeout: 1000 # maximum request processing time for all backends. - namespace: development # environment for a single backend. - service: # configuration for a single backend. - - name: trpc.test.helloworld.Greeter # backend service name. - namespace: development # backend service environment. - network: tcp # backend service network type, tcp or udp, configuration takes precedence. - protocol: trpc # application layer protocol, trpc or http. - # timeout: 800 # maximum request processing time in milliseconds. - - -plugins: # configuration for plugins. - log: # configuration for logger. - default: # default configuration for logger,,can be multiple. - - writer: console # console stdout, default. - level: debug # The level of standard output logging. - - writer: file # local file log. - level: info # The level of the local file rollover log. - formatter: json # Format of the standard output log. - writer_config: - filename: ./trpc.log # The path where the local file rolling log is stored. - max_size: 10 # The size of the local file rolling log, in MB - max_backups: 10 # Maximum number of log files - max_age: 7 # Maximum number of days to keep logs - compress: false # Whether the log file is compressed. + timeout: 2000 # maximum request processing time in milliseconds. \ No newline at end of file diff --git a/examples/features/timeout/shared/constant.go b/examples/features/timeout/shared/constant.go deleted file mode 100644 index 0f2053c1..00000000 --- a/examples/features/timeout/shared/constant.go +++ /dev/null @@ -1,18 +0,0 @@ -// -// -// Tencent is pleased to support the open source community by making tRPC available. -// -// Copyright (C) 2023 Tencent. -// All rights reserved. -// -// If you have downloaded a copy of the tRPC source code from Tencent, -// please note that tRPC source code is licensed under the Apache 2.0 License, -// A copy of the Apache 2.0 License is included in this file. -// -// - -// Package shared is the shared code for all package. -package shared - -// Addr is The server endpoint. -var Addr = "ip://127.0.0.1:8000"