You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The standard solutions to the "Thundering Herd" problem with concurrent browser initialization. The previous implementation had a couple of architectural flaws:
Massive CPU Spikes: By instantly spinning up 25 Node.js workers inside a for loop in the master process, the system had to simultaneously create 25 isolated V8 instances and start parsing files for all of them at the exact
same millisecond. This causes a massive CPU usage spike which can starve the main process and actually delay everything downstream.
Artificial Delay in Worker: Relying on the workerIndex * delay inside the worker script is generally seen as a band-aid. The V8 instances are already fighting for resources while they evaluate their file imports, only to hit
an arbitrary setTimeout when they reach the code execution phase.
A Better Implementation: Master-Coordinated Staggering
The standard practice in large-scale concurrent runners (like Playwright test and Jest worker-pools) is to stagger the creation of the worker threads themselves in the master process or use a bounded connection pool.
by removing the artificial delay logic from the worker file altogether and instead moved a 200ms delay directly into the worker-creation loop inside lib/workers.js.
• The CPU spike from spawning V8 instances is drastically smoothed out.
Why this is better:
• The master process now creates the first worker, waits 200ms, then creates the second worker, and so on.
• The browser initialization is naturally staggered because each worker starts its entire lifecycle (including imports and setups) exactly 200ms behind the previous one.
• You no longer have hacky math based on workerIndex inside your test runner script.
Users can now specify workerInitializationDelay: in their codecept.conf.js root configuration. If they omit it, it defaults to 200ms, and setting it to 0 will disable the delay entirely.
Here's an example of how a user would use this in their codecept.conf.js:
@kobenguyent One thing still worth adding: the spawn stagger is still linear and unbounded — (workers - 1) * delay, so at very high worker counts the original "grows without bound" complaint returns (just 10× milder). Could cap the total stagger window, e.g.:
That spreads all workers across at most maxStagger (default 10s) regardless of count, while preserving the per-launch spacing for normal worker counts.
@kobenguyent One thing still worth adding: the spawn stagger is still linear and unbounded — (workers - 1) * delay, so at very high worker counts the original "grows without bound" complaint returns (just 10× milder). Could cap the total stagger window, e.g.:
That spreads all workers across at most maxStagger (default 10s) regardless of count, while preserving the per-launch spacing for normal worker counts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation/Description of the PR
The standard solutions to the "Thundering Herd" problem with concurrent browser initialization. The previous implementation had a couple of architectural flaws:
same millisecond. This causes a massive CPU usage spike which can starve the main process and actually delay everything downstream.
an arbitrary setTimeout when they reach the code execution phase.
A Better Implementation: Master-Coordinated Staggering
The standard practice in large-scale concurrent runners (like Playwright test and Jest worker-pools) is to stagger the creation of the worker threads themselves in the master process or use a bounded connection pool.
by removing the artificial delay logic from the worker file altogether and instead moved a 200ms delay directly into the worker-creation loop inside lib/workers.js.
• The CPU spike from spawning V8 instances is drastically smoothed out.
Why this is better:
• The master process now creates the first worker, waits 200ms, then creates the second worker, and so on.
• The browser initialization is naturally staggered because each worker starts its entire lifecycle (including imports and setups) exactly 200ms behind the previous one.
• You no longer have hacky math based on workerIndex inside your test runner script.
Users can now specify workerInitializationDelay: in their codecept.conf.js root configuration. If they omit it, it defaults to 200ms, and setting it to 0 will disable the delay entirely.
Here's an example of how a user would use this in their codecept.conf.js:
Type of change
Checklist:
npm run docs)npm run lint)npm test)