Skip to content

fix(#295): lyra track が now-playing 不在時にハングする問題を解消#301

Merged
GeneralD merged 3 commits into
mainfrom
fix/#295-track-noinfo-hang
Jul 4, 2026
Merged

fix(#295): lyra track が now-playing 不在時にハングする問題を解消#301
GeneralD merged 3 commits into
mainfrom
fix/#295-track-noinfo-hang

Conversation

@GeneralD

@GeneralD GeneralD commented Jul 4, 2026

Copy link
Copy Markdown
Owner

agent type breaking scope diff files tests review

概要

lyra track が now-playing セッション不在時に何も出力せず無限に待ち続ける問題 (#295) を修正する。one-shot コマンドなので、空の JSON を即返して終了するのが期待動作。

根本原因

DarwinGateway.runStreamingDispatchQueue.global()GCD スレッドから continuation.yield() していた。lyra trackAsyncRunnableCommand が async→sync を DispatchSemaphore.wait() でブリッジして呼び出しスレッドを占有するため、GCD スレッドからの yield が cooperative pool の消費側 (await iterator.next()) を再開できず、初回行 ({"has_info":false}) が届かずデッドロックしていた。

  • daemon が無事だった理由: NSApplication.run() が main ランループを回し続けるため、GCD → cooperative の通知が処理されていた。
  • テストで露見しなかった理由: モック StreamingGatewayTask {} (cooperative pool) で yield するため、この越境が起きず再現しなかった。

変更内容

  • runStreaming の行配送を Task { for await line in reader.bytes.lines } に置き換え、cooperative pool 内でストリームを供給。GCD→cooperative の越境を消し、動作していた daemon / モックと同じ実行文脈に揃えた。
  • FileHandle.AsyncBytes.lines は EOF で末尾の未終端行も emit するため、行分割契約は不変 (既存テスト runStreaming yields lines and flushes final unterminated line がそのまま green)。
  • 非スロー AsyncStream<String> では読み取りエラーは意味的に EOF なので、空 catch {} ではなく try? で終端として扱う。
  • 消費側が途中で止めたら onTermination で子プロセス終了 + readerTask.cancel()

テスト計画

  • DarwinGatewayRunStreamingTests を追加 — first-line 即時配送 (lyra track が now-playing セッション不在時に出力せず待ち続ける #295 の核心) / 複数行の順序 / プロセス終了での finish を検証。.timeLimit(.minutes(1)) で万一の再ハングが CI を止めないよう保険。
  • 既存の行分割テストが無変更で green (契約不変を確認)。
  • フル swift test 1084 件 green (daemon 経路含む回帰なし)。
  • ホストで lyra track 実行 → 再生中の曲を即返し (happy-path 確認、回帰なし):
$ timeout 20 .build/debug/lyra track; echo "exit=$?"
{
  "artist" : "...",
  "title" : "...",
  ...
}
exit=0
  • 無再生シナリオの最終確認: ユニットテストは新実装の first-line 配送を証明済みで、no-session ケースも同一配送経路を通る。音楽停止状態での lyra track → 空 JSON 即返し は VM ハーネス (lyra-vm-harness.sh exec $VM -- lyra track) で最終確認する。

備考

GeneralD added 2 commits July 4, 2026 21:49
lyra track が now-playing セッション不在時に出力せず無限に待つ問題を修正。

根本原因: DarwinGateway.runStreaming が DispatchQueue.global() の GCD
スレッドから continuation.yield() していた。lyra track は
AsyncRunnableCommand が async→sync を DispatchSemaphore.wait() でブリッジし
呼び出しスレッドを占有するため、GCD スレッドからの yield が cooperative
pool の消費側 (await iterator.next()) を再開できず初回行が届かずハングした。
daemon は NSApplication.run() が main ランループを回すので露見しなかった。
テストモック StreamingGateway が Task {}(cooperative)で yield して再現し
なかったのも同根。

修正: 行配送を Task { for await line in reader.bytes.lines } に置き換え、
cooperative pool 内でストリームを供給。GCD→cooperative の越境を消し、動作
していた daemon/モックと同じ実行文脈に揃える。FileHandle.AsyncBytes.lines
は EOF で末尾の未終端行も emit するため行分割契約は不変。

- runStreaming 配送の順序・first-line 即時性・finish をユニットテストで検証
  (.timeLimit で万一の再ハングが CI を止めないよう保険)
- 実環境シナリオ(音楽不在での lyra track → 空 JSON 即返し)は VM ハーネスで確認
Copilot AI review requested due to automatic review settings July 4, 2026 12:51
@GeneralD GeneralD self-assigned this Jul 4, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@GeneralD, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 58 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6f94ca9f-573f-4f06-a4cd-49ee9d38d4f1

📥 Commits

Reviewing files that changed from the base of the PR and between 06e0a58 and f3bb360.

📒 Files selected for processing (3)
  • Sources/DarwinGateway/DarwinGateway.swift
  • Sources/VersionHandler/Resources/version.txt
  • Tests/DarwinGatewayTests/DarwinGatewayRunStreamingTests.swift
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/#295-track-noinfo-hang

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

lyra track が now-playing セッション不在時に出力ゼロのまま待ち続ける (#295) 問題を、DarwinGateway.runStreaming の実行コンテキストを GCD スレッドから Swift Concurrency の cooperative pool (Task) に寄せることで解消する PR です。CLI の one-shot 実行でもストリームの初回行が確実に配信されるようにし、デッドロックを回避します。

Changes:

  • DarwinGateway.runStreaming の行配送を FileHandle.AsyncBytes.lines + Task に置換し、cooperative pool から continuation.yield するよう変更
  • runStreaming の期待するストリーム挙動(初回行の即時配送・順序・プロセス終了時 finish)を検証するテストを追加
  • バージョンを patch bump(2.19.0 → 2.19.1)

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
Tests/DarwinGatewayTests/DarwinGatewayRunStreamingTests.swift runStreaming の即時配送・順序・終了時 finish をカバーする回帰テストを追加
Sources/DarwinGateway/DarwinGateway.swift runStreaming の読み取り/配送を Task 上に移し、CLI one-shot でのハング要因を除去
Sources/VersionHandler/Resources/version.txt fix に伴う patch bump

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +256 to +259
continuation.onTermination = { _ in
task.terminate()
readerTask.cancel()
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agent action

onTerminationtry? reader.close() を追加しました。task.terminate() の直後・readerTask.cancel() の前に置くことで、pending な await lines.next() が EOF として自然に返り、Task が自力で終了できる順序になっています。f3bb360

@codecov

codecov Bot commented Jul 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copilot 指摘 (#3523226542) への対応。
Pipe の読み取り FileHandle を deinit 任せにせず、continuation.onTermination で
`try? reader.close()` を呼ぶことで FD を確定的に解放する。
close は readerTask.cancel() の前に置くことで、pending な `await lines.next()`
が EOF として自然に返り、Task が自力で終了できるようにしている。
@GeneralD GeneralD merged commit 67e71ca into main Jul 4, 2026
5 of 6 checks passed
@GeneralD GeneralD deleted the fix/#295-track-noinfo-hang branch July 4, 2026 17:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants