gRPC调用中Deadline的本质是CancellationToken
在 C# gRPC 客户端里,
Deadline并不是独立配置项,而是通过
CancellationToken间接控制的。底层实际由 gRPC Core 的 deadline 机制驱动,但 .NET SDK 将其映射为标准的取消语义 —— 换句话说,你传一个带超时的
CancellationToken,就等效设置了 Deadline。
用CancellationTokenSource设置超时最直接
这是最常用、也最可控的方式。不要试图手动构造
Deadline对象(它只在服务端或低层 API 中出现),客户端一律走
CancellationToken。 创建
CancellationTokenSource并指定超时时间:
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));调用时传入
cts.Token:
await client.SayHelloAsync(request, cancellationToken: cts.Token);如果超时触发,抛出
RpcException,
Status.StatusCode为
DeadlineExceeded,
Status.Detail通常含 "Deadline Exceeded" 记得在不需要时调用
cts.Cancel()或
cts.Dispose(),尤其在异步未完成就丢弃请求时
避免用HttpClient.Timeout替代gRPC Deadline
HttpClient.Timeout对 gRPC 调用无效 —— 因为 gRPC over HTTP/2 使用长连接和流式语义,
HttpClient.Timeout只影响连接建立或单次请求头发送阶段,无法中断正在进行的流或等待响应的 RPC。 设置
HttpClient.Timeout = TimeSpan.FromSeconds(10)后调用
client.SayHelloAsync,若服务端卡住 15 秒,客户端仍会挂起,不会自动取消 真正生效的只有传入的
cancellationToken参数 如果你用
GrpcChannel.ForAddress自建 channel,
HttpClient配置仅影响 DNS 解析、TLS 握手等前置环节,不干预 RPC 执行期
服务端也要配合处理Cancellation
客户端设了超时,服务端若不响应取消信号,资源可能持续占用。.NET gRPC 服务默认会把
CancellationToken注入到方法参数中:
public override async Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
// context.CancellationToken 会随客户端 Deadline 自动触发
await DoWorkAsync(context.CancellationToken);
return new HelloReply { Message = "Hello" };
}务必在耗时操作(如数据库查询、HTTP 调用、
Task.Delay)中传入该 token,并检查
token.IsCancellationRequested或使用支持 cancel 的重载(如
HttpClient.GetAsync(..., token))。
没处理 cancellation 的服务端,会让客户端超时后还继续执行,既浪费资源,又可能造成状态不一致 —— 这点容易被忽略,但很关键。
