我使用此代码连接到 grpc 服务器,并且
clientConn
对象用于所有后续的 rpc 调用。 maxDelay
设置为 5 秒。现在由于服务器上的一些问题,它没有响应 grpc 调用。所以我的客户每次rpc调用都等待很长时间。我需要以不同的方式设置超时吗?
b := grpc.BackoffConfig{
MaxDelay: maxDelay,
}
clientConn, err := grpc.Dial(serverAddress, grpc.WithBackoffConfig(b), grpc.WithInsecure())
if err != nil {
log.Println("Dial failed!")
return err
}
您可以修改代码以使用
grpc.WithTimeout(5 * time.Second)
添加超时,而不是使用用于重试和重试延迟的 MaxDelay
和 grpc.WithBackoffConfig(b)
。
clientConn, err := grpc.Dial(serverAddress, grpc.WithTimeout(5 * time.Second), grpc.WithInsecure())
if err != nil {
log.Println("Dial failed!")
return err
}
但是上面的内容已被弃用,您也可以使用
DialContext
和 context.WithTimeout
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
clientConn, err := grpc.DialContext(ctx, serverAddress, grpc.WithInsecure())
if err != nil {
log.Println("Dial failed!")
return err
}
context.WithTimeout
中使用grpc.DialContext
来控制当前DialContext的所有RPC调用的超时时间。处理一个/某些特定 RPC 调用的不同超时很不方便。
我们可以定义一个自定义超时
callOption
来处理clientInterceptor
中某些RPC调用的强制超时值
通过
callOption
定义自定义超时 EmptyCallOption
type TimeoutCallOption struct {
grpc.EmptyCallOption
forcedTimeout time.Duration
}
func WithForcedTimeout(forceTimeout time.Duration) TimeoutCallOption {
return TimeoutCallOption{forcedTimeout: forceTimeout}
}
处理
forcedTimeout
中的UnaryClientInterceptor
func getForcedTimeout(callOptions []grpc.CallOption) (time.Duration, bool) {
for _, opt := range callOptions {
if co, ok := opt.(TimeoutCallOption); ok {
return co.forcedTimeout, true
}
}
return 0, false
}
func TimeoutInterceptor(t time.Duration) grpc.UnaryClientInterceptor {
return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn,
invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
timeout := t
if v, ok := getForcedTimeout(opts); ok {
timeout = v
}
if timeout <= 0 {
return invoker(ctx, method, req, reply, cc, opts...)
}
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
return invoker(ctx, method, req, reply, cc, opts...)
}
}
使用示例
// The default timeout of RPC call of this conn is 3 seconds
conn, err := grpc.Dial(
address,
grpc.WithUnaryInterceptor(TimeoutInterceptor(time.Duration(3)*time.Second)), ...)
....
c := pb.NewGreeterClient(conn)
c.SayHello(context.Background(), &pb.HelloRequest{Name: "world"},
WithForcedTimeout(time.Duration(10)*time.Second))
// The timeout of SayHello RPC call is 10 seconds
WithTimeout
的文档说它用于设置连接初始化的超时时间,而不是设置调用的超时时间。 DialContext 中的上下文是相同的。
WithTimeout 返回一个 DialOption,配置拨号超时时间 最初是 ClientConn。当且仅当 WithBlock() 为 展示。已弃用:使用 DialContext 代替 Dial 和 context.WithTimeout 代替。将在整个 1.x.
中得到支持
要设置调用超时,您可以将
context
传递给 invoke
,例如:
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(time.Duration(2000)*time.Millisecond))
defer cancel()
clientConn.Invoke(ctx, "/YourEndpoint", in, out, opts...)
使用
grpc.WithTimeout
的旧语法已被弃用。
opts := []grpc.DialOption{
// you would also need grpc.WithBlock() which can be an anti-pattern
// grpc.WithBlock(),
grpc.WithTimeout(timeoutValue),
// ...
}
clientConn, err := grpc.Dial(serverAddress, opts...)
if err != nil {
return err
}
https://pkg.go.dev/google.golang.org/grpc#WithTimeout
返回一个WithTimeout
,配置最初拨打DialOption
的超时。当且仅当ClientConn
存在时,这才有效。WithBlock()
已弃用:使用
代替DialContext
和Dial
代替。将在整个 1.x. 中得到支持context.WithTimeout
因此,如果您使用新语法,这仍然仅适用于拨打初始
ClientConn
的超时。
opts := []grpc.DialOption{
...
}
ctx, cancel := context.WithTimeout(context.Background(), timeoutValue)
clientConn, err := grpc.DialContext(ctx, serverAddress, opts...)
if err != nil {
return err
}
我使用此代码连接到 grpc 服务器,clientConn 对象用于所有后续的 rpc 调用。 maxDelay 设置为 5 秒。现在由于服务器上的一些问题,它没有响应 grpc 调用。所以我的客户每次rpc调用都等待很长时间。我需要以不同的方式设置超时吗?
如果您希望每次通话都有超时;那么这就超出了最初的
ClientConn
。您可能希望提供使用 context.WithTimeout
并将其传递给 ClientConn.Invoke
。所以你可以自己做,或者配置一个超时拦截器。
https://pkg.go.dev/google.golang.org/grpc#ClientConn.Invoke
有 2 个不错的包可用于配置常见的客户端拦截器以实现超时和重试:
import (
"context"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/timeout"
)
opts := []grpc.DialOption{
// timeout for each unary call
timeout.UnaryClientInterceptor(timeoutValue),
// ...
}
// timeout for initial ClientConn
ctx, cancel := context.WithTimeout(context.Background(), timeoutValue)
clientConn, err := grpc.DialContext(ctx, serverAddress, opts...)
if err != nil {
return err
}