Skip to content

[rush-daemon] Fix summary writer racing early coalesced results (main is red) - #6095

Open
Sean Larkin (TheLarkInn) wants to merge 1 commit into
mainfrom
thelarkinn-fix-main-summary-race
Open

Sean Larkin (TheLarkInn) wants to merge 1 commit into
mainfrom
thelarkinn-fix-main-summary-race

Conversation

@TheLarkInn

Copy link
Copy Markdown
Member

Summary

main fails 3 @rushstack/rush-daemon tests with StdioSummarizer: The summary cannot be prepared until after close() is called. Two PRs that merged close together conflict at runtime, though not textually. This PR fixes that interaction, and both features keep working.

Fixed tests:

  • PhasedRequestBatching: "publishes an early failure result while the batch continues for other clients"
  • PhasedRequestBatching: "derives shared and disjoint failure results from each client subset"
  • DaemonRequestWirePhased: "merges two connections into one shared iteration with subset-specific results"

Root cause (#6068 × #6092)

Fix

#finishSettledEntry now publishes the early result through #produceEarlyResultAsync. That function yields one microtask (await Promise.resolve()) before calling #produceResultAsync. By then the notifying record has closed its summarizer, so the summary contains the full failure tail.

Ordering and per-client correctness don't change:

  • entry.finishPromise and the unsubscribe are still set synchronously. Other participants' #needsIteration checks and the batch's #finishEntryAsync (??=) still see the early result as claimed.
  • Once unsubscribed, the entry's sink can't receive events from other operations during the yield.
  • #produceResultAsync still flushes the sink before writing the result.

rush-lib is not changed.

Tests

  • The 3 tests above pass, and their assertions are unchanged.
  • New regression test in PhasedRequestSummary.test.ts: "writes the failure summary before an early result while the coalesced batch continues". Client A's selection fails early while client C's operation is held. The test asserts:
    • A's result arrives while the graph is still executing.
    • A's output has the FAILURE banner, the --[ FAILURE: … ]-- section containing the failed operation's output, the duration line, and Operations failed.
    • The result is A's last write.
    • C then succeeds with its own summary.
  • Without the fix, the regression test fails.

Linux validation (WSL Ubuntu-24.04, fresh clone of current main @ 7a0348d)

  • Before (pristine main): heft test in rush-daemon gave 422 passed, 3 failed (the 3 above).
  • After: rush build --to @rushstack/rush-daemon --to @rushstack/rush-cli-client (includes lint) passed, then rush test --only @rushstack/rush-daemon --only @rushstack/rush-cli-client:
    • rush-daemon: 426/426 passed
    • rush-cli-client: 275/275 passed

Optional follow-ups

  • In rush-lib, consider closing stdioSummarizer/problemCollector before finalizeOperation() notifies observers. Any onOperationCompleted observer could then read a finished report synchronously.

This came out of the automated rushd Linux analysis (Rushd Hive, bugs 15 and 38). It unblocks #6065, #6066 and #6069.

The early per-client result path (#6092) runs from onOperationCompleted, which the record's finalizeOperation() invokes synchronously before closing its StdioSummarizer. The summary writer (#6068) reads the failure tail from that summarizer, so it threw. Yield once before producing the early result.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Needs triage

Development

Successfully merging this pull request may close these issues.

1 participant