Skip to content

perf(@angular/build): process batch locales sequentially in i18n inliner worker - #34211

Merged
clydin merged 2 commits into
angular:mainfrom
clydin:perf-inliner-sequential-batch
Sep 30, 2026
Merged

clydin merged 2 commits into
angular:mainfrom
clydin:perf-inliner-sequential-batch

Conversation

@clydin

@clydin clydin commented Sep 30, 2026

Copy link
Copy Markdown
Member

Executing batch locales concurrently via Promise.all within a single
worker thread provided no concurrency benefit because inlining operations
(MagicString transformations and source map decoding/remapping) are
predominantly synchronous and CPU-bound on Node's single-threaded event loop.

Holding concurrent MagicString instances, intermediate AST slices, and
decoded source map mappings simultaneously inflated peak worker heap and RSS
(especially for smaller chunks where up to 8 locales are processed in a single
batch).

Switching to sequential iteration allows intermediate transformation and
mapping structures to be garbage-collected between locales, reducing peak RSS
and slightly improving throughput due to reduced GC pressure.

…ner worker

Executing batch locales concurrently via Promise.all within a single
worker thread provided no concurrency benefit because inlining operations
(MagicString transformations and source map decoding/remapping) are
predominantly synchronous and CPU-bound on Node's single-threaded event loop.

Holding concurrent MagicString instances, intermediate AST slices, and
decoded source map mappings simultaneously inflated peak worker heap and RSS
(especially for smaller chunks where up to 8 locales are processed in a single
batch).

Switching to sequential iteration allows intermediate transformation and
mapping structures to be garbage-collected between locales, reducing peak RSS
and slightly improving throughput due to reduced GC pressure.
… files in i18n inliner

Dominant files (such as main.js or other large bundles >= 70% of max file size)
previously sharded their locales across all available workers in the pool.
On high-core machines, this dispatched heavy AST parsing and sourcemap remapping
simultaneously across all worker threads, monopolizing the pool, causing memory
bus/cache contention, and spiking peak V8 heap and RSS.

A MAX_DOMINANT_WORKERS constant of 4 now caps the number of worker threads
concurrently processing a single dominant file. Additionally, when multiple files
exist in the window, workers are dynamically allocated to guarantee that at
least one worker thread is always available to process smaller chunks concurrently
without starvation. A new multi-dominant scenario has also been added to the
benchmark suite to measure throughput and memory under multi-bundle workloads.
@clydin clydin added the target: patch This PR is targeted for the next patch release label Sep 30, 2026
@angular-robot angular-robot Bot added area: performance Issues related to performance area: @angular/build labels Sep 30, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request optimizes memory usage and concurrency management during i18n inlining. In i18n-inliner-worker.ts, parallel processing of locales via Promise.all is replaced with a sequential for...of loop to reduce peak memory. In i18n-inliner.ts, a concurrency cap (MAX_DOMINANT_WORKERS = 4) is introduced for dominant files to prevent V8 heap and RSS explosion on high-core machines, while also ensuring at least one worker remains available for smaller chunks to avoid starvation. Additionally, a new benchmark scenario (multi-dominant) is added to test these changes under contention. There are no review comments, so no further feedback is provided.

@clydin clydin added target: minor This PR is targeted for the next minor release action: review The PR is still awaiting reviews from at least one requested reviewer and removed target: patch This PR is targeted for the next patch release labels Sep 30, 2026
@clydin
clydin requested a review from alan-agius4 September 30, 2026 13:36
@alan-agius4 alan-agius4 added action: merge The PR is ready for merge by the caretaker and removed action: review The PR is still awaiting reviews from at least one requested reviewer labels Sep 30, 2026
@clydin
clydin merged commit 4f19146 into angular:main Sep 30, 2026
45 checks passed
@clydin

clydin commented Sep 30, 2026

Copy link
Copy Markdown
Member Author

This PR was merged into the repository. The changes were merged into the following branches:

@clydin
clydin deleted the perf-inliner-sequential-batch branch September 30, 2026 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action: merge The PR is ready for merge by the caretaker area: @angular/build area: performance Issues related to performance target: minor This PR is targeted for the next minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants