プロジェクト

全般

プロフィール

リファクタ #183

完了

RuntimeTaskManagerTest.shutdownInterruptsAndWaitsForTrackedTask が flaky

リファクタ #183: RuntimeTaskManagerTest.shutdownInterruptsAndWaitsForTrackedTask が flaky

エージェント ちゃん さんが23日前に追加. 22日前に更新.

ステータス:
完了
優先度:
通常
担当者:
対象バージョン:
開始日:
2026/06/13
期日:
進捗率:

100%

予定工数:

説明

概要

RuntimeTaskManagerTest.shutdownInterruptsAndWaitsForTrackedTask() が CI 上でまれに失敗する(flaky)。プロダクションコードの不具合ではなく、テストコードのレースが原因。

失敗内容

org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
  at RuntimeTaskManagerTest.shutdownInterruptsAndWaitsForTrackedTask(RuntimeTaskManagerTest.java:38)

38 行目の assertTrue(interrupted.await(1, TimeUnit.SECONDS)) が false を返す。

原因

ワーカースレッドの処理が以下の形になっている:

started.countDown();
try {
    while (!Thread.currentThread().isInterrupted()) {
        Thread.sleep(1000);
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    interrupted.countDown();
}

started.countDown() の後・Thread.sleep(1000) に入る前に manager.shutdown()thread.interrupt() を撃つと、while (!isInterrupted()) が即 false になりループ本体に入らないため Thread.sleep() が一度も呼ばれず、InterruptedException が発生しない。結果 catch 節が走らず interrupted ラッチが down せず await が失敗する。CI のように CPU が逼迫した環境で発生しやすい。

修正方針

ループ条件を外して必ず Thread.sleep を通す。Thread.sleep は割り込みフラグが立った状態で呼ばれると即座に InterruptedException を投げるため、レースが解消する:

try {
    while (true) {
        Thread.sleep(1000);
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    interrupted.countDown();
}

対象

  • src/test/java/bms/player/beatoraja/runtime/RuntimeTaskManagerTest.java

プロダクションコード(RuntimeTaskManager)の変更は不要。もう一方の startVirtualTracksAndInterruptsVirtualThread は直接 Thread.sleep を呼ぶため影響を受けない。

他の形式にエクスポート: PDF Atom