• システム開発に関わる内容をざっくりと書いていく

C# CancellationToken でタイムアウトを実装する

処理の打ち切りは CancellationToken で下流まで伝えるのが定石。タイムアウトも「一定時間後に Cancel」として同じ経路に乗せると扱いやすい。

先に結論

  • CancellationTokenSource.CancelAfterCreateLinkedTokenSource で時間切れを表現
  • トークンを HttpClient / DB / 自前ループまで渡す
  • 時間切れは多くの場合 OperationCanceledException / TaskCanceledException
  • HttpClient.Timeout と二重に切れる点に注意

基本パターン

using var cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
cts.CancelAfter(TimeSpan.FromSeconds(10));

await DoWorkAsync(cts.Token);

// または
using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
await http.GetAsync(url, timeoutCts.Token);

切り分け・実装の注意

  1. 呼び出し元の ct(リクエスト中断)と、自前タイムアウトをリンクする
  2. キャンセル後もリソース解放(using / finally)を忘れない
  3. キャッチしたら「ユーザー取消」か「時間切れ」かをログで区別
  4. 同期 Wait で塞がない。async のまま流す

よくある落とし穴

  • トークンを渡さず、上位だけ Cancel して下位が動き続ける
  • CTS を dispose し忘れ、タイマが残る
  • 時間切れを一般 Exception として握りつぶす
  • デッドロック気味の同期コンテキストでキャンセルが遅れる

関連: HttpClient タイムアウト / async/await デッドロック

ざっくりまとめ

  • タイムアウトは CancelAfter + トークン伝播
  • 例外型と「誰が切ったか」をログに残す
  • HttpClient.Timeout との役割分担を決めておく

関連記事