Skip to content

Comments

[rush-lib] Fix weighted concurrency budget being capped by operation count#5646

Open
itsnothuy wants to merge 2 commits intomicrosoft:mainfrom
itsnothuy:fix/weighted-concurrency-cap
Open

[rush-lib] Fix weighted concurrency budget being capped by operation count#5646
itsnothuy wants to merge 2 commits intomicrosoft:mainfrom
itsnothuy:fix/weighted-concurrency-cap

Conversation

@itsnothuy
Copy link

Summary

Fixes #5607 — resolves a weighted scheduling bug where the concurrency unit budget was incorrectly capped by the number of operations.

Background

When Rush uses weighted scheduling (Operation.weight > 1), the concurrency parameter in Async.forEachAsync represents a unit budget, not a task count. However, OperationExecutionManager was passing Math.min(totalOperations, parallelism), which shrinks the budget when totalOperations < parallelism.

Example: 4 operations with weight=4, parallelism=10:

  • Before: concurrency = min(4, 10) = 4 → only 1 operation fits → sequential execution
  • After: concurrency = 10 → 2 operations fit (4+4=8 ≤ 10) → parallel execution

This was reported by @LPegasus in issue #5607.

Changes

1. Fix: OperationExecutionManager.ts

  • Separated the display calculation from the scheduler's concurrency value
  • Display message now uses Math.min(totalOperations, parallelism) to avoid confusing messages like "max 10 processes" when only 4 operations exist (a UX improvement over the old code which showed raw this._parallelism)
  • Scheduler receives this._parallelism directly as the full unit budget (the core fix)

2. Tests: OperationExecutionManager.test.ts

Added 9 new tests in a "Weighted concurrency" describe block:

  1. Regression test — core bug reproduction (4 ops × w=4, p=10 → peak=2)
  2. Weight clamping — weight > budget completes without deadlock
  3. Oversubscription enabled — w=7×2, p=10 → both run concurrently
  4. Oversubscription disabled — w=7×2, p=10 → serialized
  5. Zero-weight operations — don't consume budget
  6. Mixed weights — budget accounting with varying weights
  7. Backwards compatibility — weight=1 behaves like unweighted
  8. Display message — shows capped count when parallelism > ops
  9. Display message — shows parallelism when parallelism < ops

All tests are deterministic (no timing dependencies) and use Async.sleepAsync(0) to yield control to the scheduler.

Impact

  • No API changes — purely internal fix
  • Backwards compatible — when all weights=1 (default), behavior is identical
  • No schema changes — no config file modifications needed

Testing

  • All 581 rush-lib tests pass (0 failures)
  • 9 new weighted concurrency tests pass
  • Existing snapshot tests unchanged
  • Local build: rush build --to rush-lib succeeds
  • No public API surface changes

Scope

This PR addresses only the scheduling bug. The "weight": "NN%" feature (Proposal 1 in #5607) is intentionally excluded — it requires schema changes and maintainer design approval, so it should be a separate PR.

Checklist

  • Read CONTRIBUTING.md and followed all guidelines
  • Added comprehensive tests with clear scenarios
  • Ran rush build --to rush-lib locally (passes)
  • Ran rush change and committed change file
  • Verified no public API changes
  • PR description explains the problem, solution, and testing
  • Signed Microsoft CLA

…count

test(rush-lib): expand weighted concurrency edge case tests

test(rush-lib): expand weighted concurrency edge case tests

refactor(OperationExecutionManager.test): align comment and naming style with codebase conventions

- Replace // ─── section banners and // Test N: numbered headers with brief
  inline prose comments matching the existing test file style
- Replace // WHAT: / // SCENARIO: / // DETERMINISM: structured blocks with
  concise inline comments
- Rename createWeightedOp → createWeightedOperation for consistency with
  other helper names (createExecutionManager, etc.)
- Rename counters.active / counters.peak → counters.concurrentCount /
  counters.peakConcurrency for self-documenting field names
- Extract new AbortController() calls into named abortController variables
  matching the pattern used throughout the rest of the test file
- No logic or assertion changes; all 18 tests continue to pass

chore: add rush change file for @microsoft/rush-lib weighted concurrency fix

refactor: reduce test comment density to match codebase patterns
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a weighted scheduling bug in rush-lib where the concurrency unit budget was being incorrectly reduced to the number of operations, preventing expected parallelism when Operation.weight > 1.

Changes:

  • Pass the full parallelism value as the weighted scheduler’s concurrency unit budget (no longer capped by operation count).
  • Improve the startup log message to cap the displayed “simultaneous processes” count by the number of operations (UX clarity).
  • Add a comprehensive Jest test suite covering weighted concurrency behaviors (regression, clamping, oversubscription, mixed/zero weights, and display output).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
libraries/rush-lib/src/logic/operations/OperationExecutionManager.ts Fixes the weighted scheduler’s concurrency budget and separates display calculation from scheduling.
libraries/rush-lib/src/logic/operations/test/OperationExecutionManager.test.ts Adds deterministic test coverage for weighted concurrency scenarios and logging output.
common/changes/@microsoft/rush-lib/fix_weighted-concurrency-cap_2026-02-19-07-57.json Patch change file documenting the fix for release notes/versioning.

@itsnothuy
Copy link
Author

@itsnothuy please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.

@microsoft-github-policy-service agree [company="{your company}"]

Options:

  • (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree
  • (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@microsoft-github-policy-service agree company="Microsoft"

Contributor License Agreement

@microsoft-github-policy-service agree

@iclanton
Copy link
Member

@dmichon-msft - mind reviewing this?

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.

[rush] Improve task scheduler to handle tasks that consume 100% CPU

2 participants