我正在使用此代码连接到grpc服务器,clientConn
对象用于所有后续的rpc调用。CCD_ 2被设置为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}
}
在UnaryClientInterceptor
中处理forcedTimeout
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
的doc说它用于设置连接初始化的超时,而不是为调用设置超时。DialContext中的上下文是相同的。
WithTimeout返回一个DialOption,用于配置拨号超时最初是ClientConn。当且仅当WithBlock((为目前不推荐:使用DialContext而不是Dial和上下文改为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...)