はじめに
grpc-dotnetを使用した時、通信パターンによってタイムアウトが異なっていたので備忘録として残しておく。
gRPCの通信パターン
gRPCの通信パターンは下記が存在する。
( https://learn.microsoft.com/en-us/aspnet/core/grpc/services?view=aspnetcore-10.0 より)
- 単項(Unary)
- 一リクエスト一レスポンス
- サーバーストリーミング(Server Streaming)
- 一リクエストマルチレスポンス
- クライアントストリーミング(Client Streaming)
- マルチリクエスト一レスポンス
- 双方向ストリーミング(Bidirectorical Streaming)
- マルチリクエストマルチレスポンス
タイムアウト
grpc-dotnetでは、grpcのリクエストにHttpClientを使用する。
HttpClientにはTimeoutというプロパティがあるが、これが通信パターンによって反映されるかどうかが異なる。
具体的には下記のようになる。
| パターン | Timeoutが影響するか |
|---|---|
| 単項 | Yes |
| クライアントストリーミング | Yes |
| サーバーストリーミング | No |
| 双方向ストリーミング | No |
影響する場合、 CancellationTokenを設定していても、先にTimeoutが来た場合はそちらの方が優先される ため注意が必要。
HttpClientの方のTimeoutを考慮したくない場合は、GrpcChannelOptions.HttpClientに設定するHttpClientのTimeoutの値に System.Threading.Timeout.InfiniteTimeSpan を設定すればいい。
// 例:
using var httpClient = new HttpClient(httpMessageHandler);
httpClient.Timeout = Timeout.InfiniteTimeSpan;
using var grpc = GrpcChannel.ForAddress("https://localhost:7079", new GrpcChannelOptions()
{
HttpClient = httpClient,
});
ただし、この場合はサーバーからの制御が戻ってこなくなる可能性があるため、CancellationTokenを設定するのが望ましい。
単項の場合はそれほど気にする必要はないかもしれないが、クライアントストリーミングの場合は大きいリクエストを送るケースも考えられるため、注意が必要。
今回検証に使用したソースは下記にまとめてある。
https://github.com/itn3000/grpclongrequestlabs
終わりに
HttpClient.Timeoutのことはgrpc-dotnetの方には特に言及がないため、これが出た時は驚いた。
単項とクライアントストリーミングの時でデフォルトの100秒を超えるケースというのもあまりないとは思うが、それだけに予期しないタイミングで出る場合が多いため、頭の片隅に留め置いた方が良さそう。