Skip to content

[rush] Support percentage-based weights for operationSettings in rush-project.json#5679

Merged
octogonz merged 7 commits into
microsoft:mainfrom
LPegasus:rush-pr-issue-5607
Mar 12, 2026
Merged

[rush] Support percentage-based weights for operationSettings in rush-project.json#5679
octogonz merged 7 commits into
microsoft:mainfrom
LPegasus:rush-pr-issue-5607

Conversation

@LPegasus

@LPegasus LPegasus commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Add issue #5607 proposal 1 feature.

Details

  • WeightedOperationPlugin: Added a function to convert weight settings in RushProjectConfiguration.operationSettings percentage string to integer based on os.availableParallelism().
  • WeightedOperationPlugin.test.ts: Added some tests.
  • RushProjectConfiguration.ts: Updated IOperationSettings.weight type definition.
  • rush-project.schema.json: Updated weight field json schema.
  • If the calculated result of the specified percentage has decimals, use Math.floor to round down to an integer. Maximize CPU utilization as much as possible.

How it was tested

  • Add unit test cases.
  • Tested in my test rush repo.

Impacted documentation

None

Comment thread libraries/rush-lib/src/logic/operations/test/WeightedOperationPlugin.test.ts Outdated
Comment thread libraries/rush-lib/src/schemas/rush-project.schema.json Outdated
const percentValue: number = parseFloat(weight.slice(0, -1));

// Use as much CPU as possible, so we round down the weight here
return Math.floor((percentValue / 100) * availableParallelism);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@dmichon-msft Is it okay if this rounds down to 0?

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.

I'd be tempted to suggest that if it rounds down to 0, you use the raw value just so it doesn't produce infinite parallelism, but passing floats to the concurrency engine isn't terribly advisable (you can accumulate error from adding and subtracting them). Probably restrict values to [1,Infinity) from percentage weights.

If we want to support fractional units we should redefine 1 concurrency unit as some power-of-two fraction of a CPU core (maybe 1/4?) and then propagate that all the way through the system.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I changed it to:

return Math.max(1, Math.floor((percentValue / 100) * availableParallelism));

Comment thread libraries/rush-lib/src/logic/operations/WeightedOperationPlugin.ts Outdated
Comment thread libraries/rush-lib/src/logic/operations/WeightedOperationPlugin.ts Outdated
@LPegasus LPegasus force-pushed the rush-pr-issue-5607 branch from dd7ca9a to 53b44c6 Compare March 10, 2026 09:33
1. libraries/rush-lib/src/logic/operations/WeightedOperationPlugin.ts
   - Added more comments to explain the percentage weight convert function.
   - Use `as` syntax to cast error to Error type for better readability.

2. libraries/rush-lib/src/schemas/rush-project.schema.json
    - Updated the description of the weight property to reflect that the maximum concurrency units is determined by `os.availableParallelism()`.

3. libraries/rush-lib/src/logic/operations/test/WeightedOperationPlugin.test.ts
    - Fix a test name.
@LPegasus LPegasus force-pushed the rush-pr-issue-5607 branch from 53b44c6 to 50b9ee3 Compare March 10, 2026 09:58
Comment thread libraries/rush-lib/src/logic/operations/WeightedOperationPlugin.ts Outdated
context: ICreateOperationsContext
): Map<Operation, IOperationExecutionResult> {
const { projectConfigurations } = context;
const availableParallelism: number = os.availableParallelism();

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.

I'd consider it cleaner, especially for mocking, to pass this value to the plugin constructor.

throw new Error(`Expected a percentage string like "100%".`);
}

const percentValue: number = parseFloat(weight.slice(0, -1));

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.

parseFloat doesn't mind the trailing %. Parsing stops as soon as it hits a character that isn't part of the float.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think the current code might be better; it is still correct and doesn't require the reader to have intimate knowledge of quirky API designs that were acceptable when JavaScript was first invented. :)

const percentValue: number = parseFloat(weight.slice(0, -1));

// Use as much CPU as possible, so we round down the weight here
return Math.floor((percentValue / 100) * availableParallelism);

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.

I'd be tempted to suggest that if it rounds down to 0, you use the raw value just so it doesn't produce infinite parallelism, but passing floats to the concurrency engine isn't terribly advisable (you can accumulate error from adding and subtracting them). Probably restrict values to [1,Infinity) from percentage weights.

If we want to support fractional units we should redefine 1 concurrency unit as some power-of-two fraction of a CPU core (maybe 1/4?) and then propagate that all the way through the system.

Comment on lines 66 to 68
const projectConfiguration: RushProjectConfiguration | undefined = projectConfigurations.get(project);
const operationSettings: IOperationSettings | undefined =
operation.settings ?? projectConfiguration?.operationSettingsByOperationName.get(phase.name);

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.

I find myself wondering why this layer is here; operation.settings should always already be defined if projectConfigurations.get(project)?.operationSettingsByOperationName.get(phase.name) returns a truthy value.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Seems out of scope

Comment thread libraries/rush-lib/src/schemas/rush-project.schema.json Outdated
Comment thread libraries/rush-lib/src/schemas/rush-project.schema.json Outdated
LPegasus and others added 4 commits March 12, 2026 10:35
@octogonz octogonz merged commit fb0341f into microsoft:main Mar 12, 2026
6 checks passed
@github-project-automation github-project-automation Bot moved this from Needs triage to Closed in Bug Triage Mar 12, 2026
dmichon-msft added a commit to dmichon-msft/rushstack that referenced this pull request Mar 19, 2026
…-project.json (microsoft#5679)

* feature: Support percentage-based weights for operationSettings in rush-project.json

* Resolve CodeReview comments for:

1. libraries/rush-lib/src/logic/operations/WeightedOperationPlugin.ts
   - Added more comments to explain the percentage weight convert function.
   - Use `as` syntax to cast error to Error type for better readability.

2. libraries/rush-lib/src/schemas/rush-project.schema.json
    - Updated the description of the weight property to reflect that the maximum concurrency units is determined by `os.availableParallelism()`.

3. libraries/rush-lib/src/logic/operations/test/WeightedOperationPlugin.test.ts
    - Fix a test name.

* Update libraries/rush-lib/src/schemas/rush-project.schema.json

Co-authored-by: David Michon <dmichon@microsoft.com>

* Update libraries/rush-lib/src/schemas/rush-project.schema.json

Co-authored-by: David Michon <dmichon@microsoft.com>

* PR feedback

* PR feedback

* Prepare to publish a MINOR release of Rush

---------

Co-authored-by: LPegasus <lpegasus@users.noreply.github.com>
Co-authored-by: David Michon <dmichon@microsoft.com>
Co-authored-by: Pete Gonzalez <4673363+octogonz@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Closed

Development

Successfully merging this pull request may close these issues.

3 participants