@@ -27,6 +27,14 @@ import { runtimeFeatures } from '../../lib/util/runtime-features.js'
2727 * dependencyFailed: number,
2828 * retried: number
2929 * }} TestStats
30+ *
31+ * @typedef {{
32+ * code: number | null,
33+ * signal: NodeJS.Signals | null,
34+ * stdout: Buffer[],
35+ * environment: TestEnvironment,
36+ * port: number
37+ * }} WorkerResult
3038 */
3139
3240const CLI_OPTIONS = parseArgs ( {
@@ -120,20 +128,22 @@ const testEnvironments = filterEnvironments(
120128 buildTestEnvironments ( 0 , [ CACHE_TYPES , CACHE_STORES ] )
121129)
122130
131+ // Windows runners intermittently terminate cache-test workers with 0xC0000409
132+ // when all environments run at the same time. Keep environment workers serial
133+ // there; each worker still runs the upstream cache-tests concurrently.
134+ const WORKER_CONCURRENCY = Math . max ( 1 , Number ( process . env . CACHE_TEST_WORKER_CONCURRENCY ) || (
135+ process . platform === 'win32' ? 1 : testEnvironments . length
136+ ) )
137+
123138console . log ( `Testing ${ testEnvironments . length } environments\n` )
124139console . log ( `PROTOCOL: ${ styleText ( 'gray' , PROTOCOL ) } ` )
140+ console . log ( `WORKERS: ${ styleText ( 'gray' , `${ WORKER_CONCURRENCY } ` ) } ` )
125141console . log ( '' )
126142
127143/**
128- * @type {Array<Promise<{
129- * code: number | null,
130- * signal: NodeJS.Signals | null,
131- * stdout: Buffer[],
132- * environment: TestEnvironment,
133- * port: number
134- * }>>}
144+ * @type {Array<() => Promise<WorkerResult>> }
135145 */
136- const results = [ ]
146+ const jobs = [ ]
137147
138148// Run all the tests in child processes because the test runner is a bit finicky
139149for ( let i = 0 ; i < testEnvironments . length ; i ++ ) {
@@ -182,7 +192,7 @@ for (let i = 0; i < testEnvironments.length; i++) {
182192 return promise
183193 }
184194
185- const promise = ( async ( ) => {
195+ jobs . push ( async ( ) => {
186196 const result = await runWorker ( )
187197 if ( result . signal === null && ( result . code === 0 || result . code === 1 ) ) {
188198 return result
@@ -197,16 +207,14 @@ for (let i = 0; i < testEnvironments.length; i++) {
197207 ...retryResult . stdout
198208 ]
199209 }
200- } ) ( )
201-
202- results . push ( promise )
210+ } )
203211}
204212
205213// Status code so we can fail CI jobs if we need
206214let exitCode = 0
207215
208216// Print the results of all the results in the order that they exist
209- for ( const result of await Promise . all ( results ) ) {
217+ for ( const result of await runJobs ( jobs , WORKER_CONCURRENCY ) ) {
210218 if ( result . code !== 0 || result . signal !== null ) {
211219 exitCode = result . code ?? 1
212220 }
@@ -261,6 +269,29 @@ function buildTestEnvironments (idx, testOptions) {
261269 return environments
262270}
263271
272+ /**
273+ * @param {Array<() => Promise<WorkerResult>> } jobs
274+ * @param {number } concurrency
275+ * @returns {Promise<WorkerResult[]> }
276+ */
277+ async function runJobs ( jobs , concurrency ) {
278+ const results = new Array ( jobs . length )
279+ let next = 0
280+
281+ async function worker ( ) {
282+ while ( next < jobs . length ) {
283+ const idx = next ++
284+ results [ idx ] = await jobs [ idx ] ( )
285+ }
286+ }
287+
288+ await Promise . all (
289+ Array . from ( { length : Math . min ( concurrency , jobs . length ) } , worker )
290+ )
291+
292+ return results
293+ }
294+
264295/**
265296 * @param {TestEnvironment } base
266297 * @param {TestEnvironment } sub
0 commit comments