11import os from 'os' ;
22
3+ import pLimit from 'p-limit' ;
34import Worker from 'jest-worker' ;
45import serialize from 'serialize-javascript' ;
56
@@ -9,11 +10,15 @@ const workerPath = require.resolve('./worker');
910
1011export default class TaskRunner {
1112 constructor ( options = { } ) {
13+ this . taskGenerator = options . taskGenerator ;
14+ this . files = options . files ;
1215 this . cache = options . cache ;
13- this . numberWorkers = TaskRunner . getNumberWorkers ( options . parallel ) ;
16+ this . availableNumberOfCores = TaskRunner . getAvailableNumberOfCores (
17+ options . parallel
18+ ) ;
1419 }
1520
16- static getNumberWorkers ( parallel ) {
21+ static getAvailableNumberOfCores ( parallel ) {
1722 // In some cases cpus() returns undefined
1823 // https://github.com/nodejs/node/issues/19022
1924 const cpus = os . cpus ( ) || { length : 1 } ;
@@ -31,9 +36,18 @@ export default class TaskRunner {
3136 return minify ( task ) ;
3237 }
3338
34- async run ( tasks ) {
35- if ( this . numberWorkers > 1 ) {
36- this . worker = new Worker ( workerPath , { numWorkers : this . numberWorkers } ) ;
39+ async run ( ) {
40+ const { availableNumberOfCores, cache, files, taskGenerator } = this ;
41+
42+ let concurrency = Infinity ;
43+
44+ if ( availableNumberOfCores > 0 ) {
45+ // Do not create unnecessary workers when the number of files is less than the available cores, it saves memory
46+ const numWorkers = Math . min ( files . length , availableNumberOfCores ) ;
47+
48+ concurrency = numWorkers ;
49+
50+ this . worker = new Worker ( workerPath , { numWorkers } ) ;
3751
3852 // Show syntax error from jest-worker
3953 // https://github.com/facebook/jest/issues/8872#issuecomment-524822081
@@ -44,34 +58,53 @@ export default class TaskRunner {
4458 }
4559 }
4660
47- return Promise . all (
48- tasks . map ( ( task ) => {
49- const enqueue = async ( ) => {
50- let result ;
61+ const limit = pLimit ( concurrency ) ;
62+ const scheduledTasks = [ ] ;
5163
52- try {
53- result = await this . runTask ( task ) ;
54- } catch ( error ) {
55- result = { error } ;
64+ for ( const file of files ) {
65+ const enqueue = async ( task ) => {
66+ let taskResult ;
67+
68+ try {
69+ taskResult = await this . runTask ( task ) ;
70+ } catch ( error ) {
71+ taskResult = { error } ;
72+ }
73+
74+ if ( cache . isEnabled ( ) && ! taskResult . error ) {
75+ taskResult = await cache . store ( task , taskResult ) . then (
76+ ( ) => taskResult ,
77+ ( ) => taskResult
78+ ) ;
79+ }
80+
81+ task . callback ( taskResult ) ;
82+
83+ return taskResult ;
84+ } ;
85+
86+ scheduledTasks . push (
87+ limit ( ( ) => {
88+ const task = taskGenerator ( file ) . next ( ) . value ;
89+
90+ if ( ! task ) {
91+ // Something went wrong, for example the `cacheKeys` option throw an error
92+ return Promise . resolve ( ) ;
5693 }
5794
58- if ( this . cache . isEnabled ( ) && ! result . error ) {
59- return this . cache . store ( task , result ) . then (
60- ( ) => result ,
61- ( ) => result
95+ if ( cache . isEnabled ( ) ) {
96+ return cache . get ( task ) . then (
97+ ( taskResult ) => task . callback ( taskResult ) ,
98+ ( ) => enqueue ( task )
6299 ) ;
63100 }
64101
65- return result ;
66- } ;
67-
68- if ( this . cache . isEnabled ( ) ) {
69- return this . cache . get ( task ) . then ( ( data ) => data , enqueue ) ;
70- }
102+ return enqueue ( task ) ;
103+ } )
104+ ) ;
105+ }
71106
72- return enqueue ( ) ;
73- } )
74- ) ;
107+ return Promise . all ( scheduledTasks ) ;
75108 }
76109
77110 async exit ( ) {
0 commit comments