代码之家  ›  专栏  ›  技术社区  ›  dan-kli

如何为gRPC客户端工厂创建的gRPC客户端设置通用截止日期?

  •  1
  • dan-kli  · 技术社区  · 2 年前

    沿着 gRPC client factory integration in .NET 我可以这样注册一个gRPC客户端:

    builder.Services.AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    });
    

    现在我想设定一个通用 deadline 对于使用此客户端进行的所有呼叫。也许是这样的:

    int deadline = ReadFromConfig();
    
    builder.Services.AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
        o.CallOptionsActions.Add(o => 
            o.CallOptions.Deadline = DateTime.UtcNow.AddSeconds(deadline))
    });
    

    但是,调用选项中的截止日期在此处是只读的。好像我不能把它放在这里。我做错了吗,还是只能在发送请求时设定截止日期?

    1 回复  |  直到 2 年前
        1
  •  2
  •   Marc Gravell    2 年前

    完全未经测试,但怎么样 Interceptor ?

    var channel = GrpcChannel.ForAddress("https://whatever");
    var invoker = channel.Intercept(new DeadlineInterceptor(TimeSpan.FromSeconds(10)));
    // TODO: create your client from "invoker", not "channel"
    
    
    class DeadlineInterceptor(TimeSpan deadline) : Interceptor
    {
        private void ApplyDeadline<TRequest, TResponse>(ref ClientInterceptorContext<TRequest, TResponse> context)
            where TRequest : class
            where TResponse : class
        {
            if (context.Options.Deadline is null)
            {
                context = new(context.Method, context.Host, context.Options.WithDeadline(DateTime.UtcNow.Add(deadline)));
            }
        }
    
        public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
        {
            ApplyDeadline(ref context);
            return base.AsyncClientStreamingCall(context, continuation);
        }
    
        public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncDuplexStreamingCallContinuation<TRequest, TResponse> continuation)
        {
            ApplyDeadline(ref context);
            return base.AsyncDuplexStreamingCall(context, continuation);
        }
    
        public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation)
        {
            ApplyDeadline(ref context);
            return base.AsyncServerStreamingCall(request, context, continuation);
        }
    
        public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
        {
            ApplyDeadline(ref context);
            return base.AsyncUnaryCall(request, context, continuation);
        }
    
        public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
        {
            ApplyDeadline(ref context);
            return base.BlockingUnaryCall(request, context, continuation);
        }
    
        // note no need to intercept server methods
    }