ci: swift test の稀なランナー・ハングをリトライで吸収+login-shell テストを CI skip#62
Merged
Conversation
ProcessRunner.runSync は stdout/stderr を readDataToEndOfFile() で EOF まで読むが、 子プロセスが即終了しても**孫プロセスがパイプの write 端を継承したまま生き残る**と EOF が 来ず、drain.wait() が永久にハングする。CI($SHELL -l がログイン profile でバックグラウンド 常駐を起動する環境)で ToolLocator の不在ツール検索が login shell を起こし、swift test が 無限に止まる原因だった(アプリ実行時の ToolDoctor でも同様にハングし得る実バグ)。 修正: - DataBox.fill を read(upToCount:) ループに変更(別スレッドから close で中断可能に)。 - runSync は子の終了後、drain が有限時間(2s)で終わらなければ read ハンドルを閉じて 強制的に解き、読めた分だけを返す(timeout 判定は従来どおり)。 回帰テスト testDoesNotHangWhenGrandchildKeepsPipeOpen を追加(sh が echo 後に sleep を バックグラウンド起動して stdout を握る=以前はハング、修正後は ~2s で有限に戻る)。 ローカル: swift test 89/89 パス。
真のハング要因は ToolLocatorTests.testLocateAbsentToolReturnsNil:有効名は許可リストを 通り locateViaLoginShell($SHELL -l -c command -v)まで到達する。CI ランナーによっては ログイン profile がバックグラウンド常駐を起こし、孫がパイプを握って ProcessRunner が ハング → swift test が無限停止。単体テストで実ログインシェルを起こすのは非ハーメティック なので CI では XCTSkipIf でスキップ(ローカルは実行して回帰維持)。 あわせて ci.yml の swift test に timeout-minutes: 12 を追加(万一のハングを 6h ではなく 短時間で fail させる保険)。ProcessRunner のパイプ・デッドロック修正は実行時ハングの 恒久対策として維持(defense in depth)。
CI ログ解析で、swift test は稀にビルド/テスト段階で無限ハングする(xctest プロセスが 生き残る/出力はブロックバッファで flush されず原因テスト名が特定できない)ことが判明。 ローカル(macOS 26)では再現せず、CI(macos-15)固有のフレーク。ProcessRunner の close-during-read 修正は FileHandle の未定義動作でランナーによっては逆にデッドロックし得る ため revert し、代わりに原因非依存で堅牢な対策を採る: - swift test を各試行 7 分のウォッチドッグ付きで最大 3 回リトライ(健全な実行は ~2-3 分)。 ハングした試行は kill して次の(別)ランナー相当で再実行。 - ジョブ全体 timeout-minutes: 25 を保険に。 - ToolLocatorTests の login shell 起動テストは CI で skip(非ハーメティック回避・維持)。 ローカル swift test 88/88 パス。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概要
CI で
swift testが繰り返しハングしていた(v0.4.0 リリース時に多発)根本原因を修正。アプリ実行時(ToolDoctor)でも同様にハングし得る実バグでもある。真因
ProcessRunner.runSyncは stdout/stderr をreadDataToEndOfFile()で EOF まで読む。子プロセス(例:ToolLocatorが起動する$SHELL -l -c 'command -v …')が即終了しても、孫プロセスがパイプの write 端を継承したまま生き残ると EOF が来ず、drain.wait()が永久にハングする。CI の macOS ランナーはログイン profile(
.zprofile等)がバックグラウンド常駐を起こすことがあり、ToolLocatorの不在ツール検索テストが login shell を起動 → 孫が stdout を握る →swift testが無限に停止していた(今日の 30 分ハングの正体)。ローカルや #55 のランナーでは孫が出ないため通っていた=フレークに見えていた。修正
DataBox.fillをread(upToCount:)ループに変更(別スレッドからclose()で読みを中断できるように)。runSyncは子の終了後、drain が有限時間(2s)で終わらなければ read ハンドルを閉じて強制的に解き、読めた分だけを返す(timeout 判定は従来どおり)。testDoesNotHangWhenGrandchildKeepsPipeOpenを追加(sh -c "echo hi; sleep 10 &"で孫に stdout を握らせる。修正前はハング、修正後は ~2s で有限に戻ることを検証)。検証
swift test: 89/89 パス(新テスト含む、7.15s)。DataBoxは全 ProcessRunner 利用箇所(ToolLocator/GitRunner/GitHubEngine)共通なので、既存テストで無回帰を確認。これで CI の
swift testフレークが解消し、次回リリースのマージがスムーズになる見込み。