🐣

[capnp][kj]タイムアウト処理

に公開

注意 : 今回作成した timeoutSafe は終了しないタスクはタイムアウトできないので注意.

概要

レスポンスを待つ場合に処理をタイムアウトさせたい場合がある.
その時 kj::Timer::afterDelay() を使って規定時間経過後処理を止めることができた.

サンプルソースコード
https://github.com/nagato0614/capnp/blob/main/src/delay_example.cpp

結論

以下の様な形でタイムアウトを設定させたい task を渡して上げて, timer とタイムアウト時間を指定する.

kj::Promise<bool> timeoutSafe(kj::Promise<void>&& task, kj::Timer& timer,
                              kj::Duration timeout) {
  auto timeoutPromise = timer.afterDelay(timeout).then([]() {
    LOG_COUT << "[ReusableTask] Timeout : Task timed out.\n";
    return false;
  });

  return kj::mv(task)
      .then([]() {
        LOG_COUT << "[ReusableTask] Timeout : Task completed successfully.\n";
        return true;
      })
      .exclusiveJoin(kj::mv(timeoutPromise));
}

ソースコード解説

以下の部分でタイムアウト用のタイマーを作成している.
今回は, タイムアウト完了したというメッセージを表示.
これは普通のタイマーの使い方と同じ.

  auto timeoutPromise = timer.afterDelay(timeout).then([]() {
    LOG_COUT << "[ReusableTask] Timeout : Task timed out.\n";
    return false;
  });

return 部分がタイムアウトさせるための処理.
2つのタスクが存在する.

  • task : 処理に時間がかかるタスク.
  • timeoutPromise : タイムアウト時間を計測するタスク

この task, timeoutPromise のどちらかが先に完了した時点での結果を返す.
これによってタイムアウトを実現することができる.
exclusiveJoin 使用せずに wait でも似たような動作になったが
その場合タイムアウトしたときに例外が送出されてしまった.

  return kj::mv(task)
      .then([]() {
        LOG_COUT << "[ReusableTask] Timeout : Task completed successfully.\n";
        return true;
      })
      .exclusiveJoin(kj::mv(timeoutPromise));

最後に

exclusiveJoin を使用して3つ以上のタスクを待てるかどうかは確認できていない.

Discussion