Following along the gRPC client factory integration in .NET I can register a gRPC client like this:
builder.Services.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
});
Now I would like to set a universal deadline for all calls that are made with this client. Maybe something like this:
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))
});
However, the deadline in the call options is read-only here. It seems like I cannot set it here. Am I doing it wrong, or is it only possible to set a deadline when sending out the request?
Completely untested, but how about an 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
}