デッドライン、キャンセルとインターセプター
デッドラインでタイムアウトを適用し、CancellationTokenを伝播させ、gRPCインターセプターで横断的関心事を追加します。
「デッドライン、キャンセルとインターセプター」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。
gRPC の信頼性: デッドラインとキャンセル
本番環境の gRPC サービスでは、2 つの重要な信頼性上の問題に対処する必要があります。デッドライン(クライアントが待機する時間)とキャンセル(処理を早期に停止すること)です。これらを組み合わせることで、リソースの枯渇や障害の連鎖を防げます。
呼び出しにデッドラインを設定する
デッドラインとは、呼び出しを完了しなければならない絶対時刻です。CallOptions を使用して設定します。期限を超えると、サーバーはキャンセルを受け取り、クライアントは StatusCode.DeadlineExceeded を受け取ります。
var deadline = DateTime.UtcNow.AddSeconds(5);
var reply = await client.GetOrderAsync(
new GetOrderRequest { Id = 42 },
deadline: deadline);
// Or via CallOptions:
var options = new CallOptions(deadline: deadline);
var reply2 = await client.GetOrderAsync(
new GetOrderRequest { Id = 42 }, options);クライアントで DeadlineExceeded を処理する
RpcException をキャッチし、ステータスコードを確認して、デッドラインの超過とその他のエラーを区別します。
try
{
var reply = await client.GetOrderAsync(
new GetOrderRequest { Id = 42 },
deadline: DateTime.UtcNow.AddSeconds(3));
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.DeadlineExceeded)
{
Console.WriteLine("Call timed out");
}
catch (RpcException ex)
{
Console.WriteLine($"gRPC error: {ex.Status.Detail}");
}サーバーでデッドラインを尊重する
サーバーでは、時間のかかる処理中に context.CancellationToken を確認する必要があります。デッドラインを過ぎると、このトークンは自動的にキャンセルされます。
public override async Task<ReportResponse> GenerateReport(
ReportRequest request,
ServerCallContext context)
{
var ct = context.CancellationToken;
// Pass ct to every async call — work stops when deadline hits
var data = await _db.FetchLargeDatasetAsync(request.Filters, ct);
var report = await _reportEngine.BuildAsync(data, ct);
ct.ThrowIfCancellationRequested(); // explicit check before CPU work
return MapToResponse(report);
}CancellationToken の伝播
サーバーのキャンセル トークンは、すべての非同期呼び出しチェーンを通じて必ず伝播してください。無視すると、キャンセルされた呼び出しが不必要にリソースを消費し続けます。
// GOOD: token flows through the call chain
await _db.Products.AsNoTracking()
.Where(p => p.IsActive)
.ToListAsync(context.CancellationToken); // cancels if client disconnects
// BAD: ignores cancellation
await _db.Products.ToListAsync(); // keeps running after deadlinegRPC インターセプター: 概念
インターセプターは ASP.NET Core のミドルウェアに相当する gRPC の仕組みです。RPC 呼び出しの前後で実行され、リクエスト、レスポンス、例外を検査または変更できます。ログ記録、認証、再試行ロジックに適しています。
サーバー側インターセプターを作成する
Interceptor を継承し、インターセプトするメソッドの種類をオーバーライドします。実際のハンドラーに処理を進めるには continuation を呼び出します。
using Grpc.Core.Interceptors;
public class LoggingInterceptor : Interceptor
{
private readonly ILogger<LoggingInterceptor> _logger;
public LoggingInterceptor(ILogger<LoggingInterceptor> l) => _logger = l;
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
TRequest request,
ServerCallContext context,
UnaryServerMethod<TRequest, TResponse> continuation)
{
_logger.LogInformation("gRPC call: {Method}", context.Method);
var sw = System.Diagnostics.Stopwatch.StartNew();
var response = await continuation(request, context);
_logger.LogInformation("Completed in {Ms}ms", sw.ElapsedMilliseconds);
return response;
}
}サーバーインターセプターを登録する
Program.cs でインターセプターをグローバル(すべてのサービス対象)またはサービス単位で登録します。DI コンテナーがコンストラクターの依存関係を解決します。
// Globally for all gRPC services:
builder.Services.AddGrpc(opt =>
opt.Interceptors.Add<LoggingInterceptor>());
// Or per service:
builder.Services.AddGrpc();
builder.Services.AddSingleton<LoggingInterceptor>();
app.MapGrpcService<OrderService>()
.AddInterceptor<LoggingInterceptor>();クライアント側インターセプター
クライアントインターセプターは送信する呼び出しをラップします。各呼び出し元を変更することなく、認証ヘッダー、再試行ロジック、相関 ID を追加できるため便利です。
public class AuthInterceptor : Interceptor
{
private readonly ITokenProvider _tokens;
public AuthInterceptor(ITokenProvider t) => _tokens = t;
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
var headers = context.Options.Headers ?? new Metadata();
headers.Add("authorization", $"Bearer {_tokens.GetToken()}");
var newContext = new ClientInterceptorContext<TRequest, TResponse>(
context.Method, context.Host,
context.Options.WithHeaders(headers));
return continuation(request, newContext);
}
}
// Attach to channel:
var invoker = channel.Intercept(new AuthInterceptor(tokenProvider));
var client = new OrderService.OrderServiceClient(invoker);例外インターセプター
サーバー側の例外インターセプターは、処理されていない例外を RpcExceptions に変換し、内部の詳細がクライアントに漏洩するのを防ぎます。
public class ExceptionInterceptor : Interceptor
{
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
TRequest request,
ServerCallContext context,
UnaryServerMethod<TRequest, TResponse> continuation)
{
try
{
return await continuation(request, context);
}
catch (NotFoundException ex)
{
throw new RpcException(new Status(StatusCode.NotFound, ex.Message));
}
catch (Exception ex)
{
throw new RpcException(new Status(StatusCode.Internal, "Internal error"));
}
}
}確認問題
gRPC 呼び出しがデッドラインを超えると何が起こりますか?
まとめ: デッドライン、キャンセル、インターセプター
重要なポイント:
- 待機時間に上限がなくなるのを防ぐため、クライアントの呼び出しには必ずデッドラインを設定する
- サーバーで
context.CancellationTokenを確認し、すべての非同期呼び出しに渡す - インターセプターを使用すると、サービスコードを複雑にせずに横断的関心事(ログ記録、認証、エラーマッピング)を処理できる
- サーバーインターセプター: Unary/Stream ハンドラーメソッドをオーバーライドし、
continuationを呼び出す - クライアントインターセプター: チャネルの呼び出し元チェーンにアタッチする
よくある質問
「デッドライン、キャンセルとインターセプター」レッスンは無料ですか?
はい。「デッドライン、キャンセルとインターセプター」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。
「デッドライン、キャンセルとインターセプター」で何を学びますか?
デッドラインでタイムアウトを適用し、CancellationTokenを伝播させ、gRPCインターセプターで横断的関心事を追加します。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C# Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「デッドライン、キャンセルとインターセプター」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC# Academyレッスンでコードを書いて実行できますか?
はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- gRPCとProtobufの基礎
- UnaryとサーバーストリーミングRPC
- クライアントと双方向ストリーミング
- デッドライン、キャンセルとインターセプター