@parcel/workers 2.0.0-nightly.92 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
package/src/WorkerFarm.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  restoreDeserializedObject,
21
21
  serialize,
22
22
  } from '@parcel/core';
23
- import ThrowableDiagnostic, {anyToDiagnostic} from '@parcel/diagnostic';
23
+ import ThrowableDiagnostic, {anyToDiagnostic, md} from '@parcel/diagnostic';
24
24
  import Worker, {type WorkerCall} from './Worker';
25
25
  import cpuCount from './cpuCount';
26
26
  import Handle from './Handle';
@@ -31,9 +31,10 @@ import Trace from './Trace';
31
31
  import fs from 'fs';
32
32
  import logger from '@parcel/logger';
33
33
 
34
- let profileId = 1;
35
34
  let referenceId = 1;
36
35
 
36
+ export opaque type SharedReference = number;
37
+
37
38
  export type FarmOptions = {|
38
39
  maxConcurrentWorkers: number,
39
40
  maxConcurrentCallsPerWorker: number,
@@ -42,7 +43,7 @@ export type FarmOptions = {|
42
43
  warmWorkers: boolean,
43
44
  workerPath?: FilePath,
44
45
  backend: BackendType,
45
- patchConsole?: boolean,
46
+ shouldPatchConsole?: boolean,
46
47
  |};
47
48
 
48
49
  type WorkerModule = {|
@@ -52,7 +53,8 @@ type WorkerModule = {|
52
53
  export type WorkerApi = {|
53
54
  callMaster(CallRequest, ?boolean): Promise<mixed>,
54
55
  createReverseHandle(fn: HandleFunction): Handle,
55
- getSharedReference(ref: number): mixed,
56
+ getSharedReference(ref: SharedReference): mixed,
57
+ resolveSharedReference(value: mixed): ?SharedReference,
56
58
  callChild?: (childId: number, request: HandleCallRequest) => Promise<mixed>,
57
59
  |};
58
60
 
@@ -66,12 +68,14 @@ export default class WorkerFarm extends EventEmitter {
66
68
  callQueue: Array<WorkerCall> = [];
67
69
  ending: boolean = false;
68
70
  localWorker: WorkerModule;
71
+ localWorkerInit: ?Promise<void>;
69
72
  options: FarmOptions;
70
73
  run: HandleFunction;
71
74
  warmWorkers: number = 0;
72
75
  workers: Map<number, Worker> = new Map();
73
76
  handles: Map<number, Handle> = new Map();
74
- sharedReferences: Map<number, mixed> = new Map();
77
+ sharedReferences: Map<SharedReference, mixed> = new Map();
78
+ sharedReferencesByValue: Map<mixed, SharedReference> = new Map();
75
79
  profiler: ?Profiler;
76
80
 
77
81
  constructor(farmOptions: $Shape<FarmOptions> = {}) {
@@ -92,12 +96,24 @@ export default class WorkerFarm extends EventEmitter {
92
96
 
93
97
  // $FlowFixMe this must be dynamic
94
98
  this.localWorker = require(this.options.workerPath);
99
+ this.localWorkerInit =
100
+ this.localWorker.childInit != null ? this.localWorker.childInit() : null;
95
101
  this.run = this.createHandle('run');
96
102
 
97
103
  this.startMaxWorkers();
98
104
  }
99
105
 
100
- workerApi = {
106
+ workerApi: {|
107
+ callChild: (childId: number, request: HandleCallRequest) => Promise<mixed>,
108
+ callMaster: (
109
+ request: CallRequest,
110
+ awaitResponse?: ?boolean,
111
+ ) => Promise<mixed>,
112
+ createReverseHandle: (fn: HandleFunction) => Handle,
113
+ getSharedReference: (ref: SharedReference) => mixed,
114
+ resolveSharedReference: (value: mixed) => void | SharedReference,
115
+ runHandle: (handle: Handle, args: Array<any>) => Promise<mixed>,
116
+ |} = {
101
117
  callMaster: async (
102
118
  request: CallRequest,
103
119
  awaitResponse: ?boolean = true,
@@ -120,7 +136,15 @@ export default class WorkerFarm extends EventEmitter {
120
136
  retries: 0,
121
137
  });
122
138
  }),
123
- getSharedReference: (ref: number) => this.sharedReferences.get(ref),
139
+ runHandle: (handle: Handle, args: Array<any>): Promise<mixed> =>
140
+ this.workerApi.callChild(nullthrows(handle.childId), {
141
+ handle: handle.id,
142
+ args,
143
+ }),
144
+ getSharedReference: (ref: SharedReference) =>
145
+ this.sharedReferences.get(ref),
146
+ resolveSharedReference: (value: mixed) =>
147
+ this.sharedReferencesByValue.get(value),
124
148
  };
125
149
 
126
150
  warmupWorker(method: string, args: Array<any>): void {
@@ -152,7 +176,7 @@ export default class WorkerFarm extends EventEmitter {
152
176
  }
153
177
 
154
178
  createHandle(method: string): HandleFunction {
155
- return (...args) => {
179
+ return async (...args) => {
156
180
  // Child process workers are slow to start (~600ms).
157
181
  // While we're waiting, just run on the main thread.
158
182
  // This significantly speeds up startup time.
@@ -166,15 +190,22 @@ export default class WorkerFarm extends EventEmitter {
166
190
  let processedArgs = restoreDeserializedObject(
167
191
  prepareForSerialization([...args, false]),
168
192
  );
193
+
194
+ if (this.localWorkerInit != null) {
195
+ await this.localWorkerInit;
196
+ this.localWorkerInit = null;
197
+ }
169
198
  return this.localWorker[method](this.workerApi, ...processedArgs);
170
199
  }
171
200
  };
172
201
  }
173
202
 
174
- onError(error: ErrorWithCode, worker: Worker) {
203
+ onError(error: ErrorWithCode, worker: Worker): void | Promise<void> {
175
204
  // Handle ipc errors
176
205
  if (error.code === 'ERR_IPC_CHANNEL_CLOSED') {
177
206
  return this.stopWorker(worker);
207
+ } else {
208
+ logger.error(error, '@parcel/workers');
178
209
  }
179
210
  }
180
211
 
@@ -182,7 +213,8 @@ export default class WorkerFarm extends EventEmitter {
182
213
  let worker = new Worker({
183
214
  forcedKillTime: this.options.forcedKillTime,
184
215
  backend: this.options.backend,
185
- patchConsole: this.options.patchConsole,
216
+ shouldPatchConsole: this.options.shouldPatchConsole,
217
+ sharedReferences: this.sharedReferences,
186
218
  });
187
219
 
188
220
  worker.fork(nullthrows(this.options.workerPath));
@@ -227,7 +259,11 @@ export default class WorkerFarm extends EventEmitter {
227
259
  this.startChild();
228
260
  }
229
261
 
230
- for (let worker of this.workers.values()) {
262
+ let workers = [...this.workers.values()].sort(
263
+ (a, b) => a.calls.size - b.calls.size,
264
+ );
265
+
266
+ for (let worker of workers) {
231
267
  if (!this.callQueue.length) {
232
268
  break;
233
269
  }
@@ -251,7 +287,7 @@ export default class WorkerFarm extends EventEmitter {
251
287
  let {method, args, location, awaitResponse, idx, handle: handleId} = data;
252
288
  let mod;
253
289
  if (handleId != null) {
254
- mod = nullthrows(this.handles.get(handleId)).fn;
290
+ mod = nullthrows(this.handles.get(handleId)?.fn);
255
291
  } else if (location) {
256
292
  // $FlowFixMe this must be dynamic
257
293
  mod = require(location);
@@ -282,7 +318,6 @@ export default class WorkerFarm extends EventEmitter {
282
318
  }
283
319
  } else {
284
320
  // ESModule default interop
285
- // $FlowFixMe
286
321
  if (mod.__esModule && !mod[method] && mod.default) {
287
322
  mod = mod.default;
288
323
  }
@@ -327,15 +362,17 @@ export default class WorkerFarm extends EventEmitter {
327
362
  async end(): Promise<void> {
328
363
  this.ending = true;
329
364
 
365
+ await Promise.all(
366
+ Array.from(this.workers.values()).map(worker => this.stopWorker(worker)),
367
+ );
368
+
330
369
  for (let handle of this.handles.values()) {
331
370
  handle.dispose();
332
371
  }
333
372
  this.handles = new Map();
334
373
  this.sharedReferences = new Map();
374
+ this.sharedReferencesByValue = new Map();
335
375
 
336
- await Promise.all(
337
- Array.from(this.workers.values()).map(worker => this.stopWorker(worker)),
338
- );
339
376
  this.ending = false;
340
377
  }
341
378
 
@@ -357,28 +394,28 @@ export default class WorkerFarm extends EventEmitter {
357
394
  );
358
395
  }
359
396
 
360
- createReverseHandle(fn: HandleFunction) {
361
- let handle = new Handle({fn, workerApi: this.workerApi});
397
+ createReverseHandle(fn: HandleFunction): Handle {
398
+ let handle = new Handle({fn});
362
399
  this.handles.set(handle.id, handle);
363
400
  return handle;
364
401
  }
365
402
 
366
- async createSharedReference(value: mixed) {
403
+ async createSharedReference(
404
+ value: mixed,
405
+ // An optional, pre-serialized representation of the value to be used
406
+ // in its place.
407
+ buffer?: Buffer,
408
+ ): Promise<{|ref: SharedReference, dispose(): Promise<mixed>|}> {
367
409
  let ref = referenceId++;
368
410
  this.sharedReferences.set(ref, value);
411
+ this.sharedReferencesByValue.set(value, ref);
412
+
413
+ let toSend = buffer ? buffer.buffer : value;
369
414
  let promises = [];
370
415
  for (let worker of this.workers.values()) {
371
- promises.push(
372
- new Promise((resolve, reject) => {
373
- worker.call({
374
- method: 'createSharedReference',
375
- args: [ref, value],
376
- resolve,
377
- reject,
378
- retries: 0,
379
- });
380
- }),
381
- );
416
+ if (worker.ready) {
417
+ promises.push(worker.sendSharedReference(ref, toSend));
418
+ }
382
419
  }
383
420
 
384
421
  await Promise.all(promises);
@@ -387,6 +424,7 @@ export default class WorkerFarm extends EventEmitter {
387
424
  ref,
388
425
  dispose: () => {
389
426
  this.sharedReferences.delete(ref);
427
+ this.sharedReferencesByValue.delete(value);
390
428
  let promises = [];
391
429
  for (let worker of this.workers.values()) {
392
430
  promises.push(
@@ -396,6 +434,7 @@ export default class WorkerFarm extends EventEmitter {
396
434
  args: [ref],
397
435
  resolve,
398
436
  reject,
437
+ skipReadyCheck: true,
399
438
  retries: 0,
400
439
  });
401
440
  }),
@@ -417,6 +456,7 @@ export default class WorkerFarm extends EventEmitter {
417
456
  resolve,
418
457
  reject,
419
458
  retries: 0,
459
+ skipReadyCheck: true,
420
460
  });
421
461
  }),
422
462
  );
@@ -446,6 +486,7 @@ export default class WorkerFarm extends EventEmitter {
446
486
  resolve,
447
487
  reject,
448
488
  retries: 0,
489
+ skipReadyCheck: true,
449
490
  });
450
491
  }),
451
492
  );
@@ -453,7 +494,7 @@ export default class WorkerFarm extends EventEmitter {
453
494
 
454
495
  var profiles = await Promise.all(promises);
455
496
  let trace = new Trace();
456
- let filename = `profile-${profileId++}.trace`;
497
+ let filename = `profile-${getTimeId()}.trace`;
457
498
  let stream = trace.pipe(fs.createWriteStream(filename));
458
499
 
459
500
  for (let profile of profiles) {
@@ -467,21 +508,84 @@ export default class WorkerFarm extends EventEmitter {
467
508
 
468
509
  logger.info({
469
510
  origin: '@parcel/workers',
470
- message: `Wrote profile to ${filename}`,
511
+ message: md`Wrote profile to ${filename}`,
471
512
  });
472
513
  }
473
514
 
474
- static getNumWorkers() {
515
+ async callAllWorkers(method: string, args: Array<any>) {
516
+ let promises = [];
517
+ for (let worker of this.workers.values()) {
518
+ promises.push(
519
+ new Promise((resolve, reject) => {
520
+ worker.call({
521
+ method,
522
+ args,
523
+ resolve,
524
+ reject,
525
+ retries: 0,
526
+ });
527
+ }),
528
+ );
529
+ }
530
+
531
+ promises.push(this.localWorker[method](this.workerApi, ...args));
532
+ await Promise.all(promises);
533
+ }
534
+
535
+ async takeHeapSnapshot() {
536
+ let snapshotId = getTimeId();
537
+
538
+ try {
539
+ let snapshotPaths = await Promise.all(
540
+ [...this.workers.values()].map(
541
+ worker =>
542
+ new Promise((resolve, reject) => {
543
+ worker.call({
544
+ method: 'takeHeapSnapshot',
545
+ args: [snapshotId],
546
+ resolve,
547
+ reject,
548
+ retries: 0,
549
+ skipReadyCheck: true,
550
+ });
551
+ }),
552
+ ),
553
+ );
554
+
555
+ logger.info({
556
+ origin: '@parcel/workers',
557
+ message: md`Wrote heap snapshots to the following paths:\n${snapshotPaths.join(
558
+ '\n',
559
+ )}`,
560
+ });
561
+ } catch {
562
+ logger.error({
563
+ origin: '@parcel/workers',
564
+ message: 'Unable to take heap snapshots. Note: requires Node 11.13.0+',
565
+ });
566
+ }
567
+ }
568
+
569
+ static getNumWorkers(): number {
475
570
  return process.env.PARCEL_WORKERS
476
571
  ? parseInt(process.env.PARCEL_WORKERS, 10)
477
- : cpuCount();
572
+ : Math.ceil(cpuCount() / 2);
478
573
  }
479
574
 
480
- static isWorker() {
575
+ static isWorker(): boolean {
481
576
  return !!child;
482
577
  }
483
578
 
484
- static getWorkerApi() {
579
+ static getWorkerApi(): {|
580
+ callMaster: (
581
+ request: CallRequest,
582
+ awaitResponse?: ?boolean,
583
+ ) => Promise<mixed>,
584
+ createReverseHandle: (fn: (...args: Array<any>) => mixed) => Handle,
585
+ getSharedReference: (ref: SharedReference) => mixed,
586
+ resolveSharedReference: (value: mixed) => void | SharedReference,
587
+ runHandle: (handle: Handle, args: Array<any>) => Promise<mixed>,
588
+ |} {
485
589
  invariant(
486
590
  child != null,
487
591
  'WorkerFarm.getWorkerApi can only be called within workers',
@@ -489,7 +593,20 @@ export default class WorkerFarm extends EventEmitter {
489
593
  return child.workerApi;
490
594
  }
491
595
 
492
- static getConcurrentCallsPerWorker() {
493
- return parseInt(process.env.PARCEL_MAX_CONCURRENT_CALLS, 10) || 5;
596
+ static getConcurrentCallsPerWorker(): number {
597
+ return parseInt(process.env.PARCEL_MAX_CONCURRENT_CALLS, 10) || 30;
494
598
  }
495
599
  }
600
+
601
+ function getTimeId() {
602
+ let now = new Date();
603
+ return (
604
+ String(now.getFullYear()) +
605
+ String(now.getMonth() + 1).padStart(2, '0') +
606
+ String(now.getDate()).padStart(2, '0') +
607
+ '-' +
608
+ String(now.getHours()).padStart(2, '0') +
609
+ String(now.getMinutes()).padStart(2, '0') +
610
+ String(now.getSeconds()).padStart(2, '0')
611
+ );
612
+ }
package/src/backend.js CHANGED
@@ -2,6 +2,12 @@
2
2
  import type {BackendType, WorkerImpl} from './types';
3
3
 
4
4
  export function detectBackend(): BackendType {
5
+ switch (process.env.PARCEL_WORKER_BACKEND) {
6
+ case 'threads':
7
+ case 'process':
8
+ return process.env.PARCEL_WORKER_BACKEND;
9
+ }
10
+
5
11
  try {
6
12
  require('worker_threads');
7
13
  return 'threads';
package/src/bus.js CHANGED
@@ -20,4 +20,4 @@ class Bus extends EventEmitter {
20
20
  }
21
21
  }
22
22
 
23
- export default new Bus();
23
+ export default (new Bus(): Bus);
package/src/child.js CHANGED
@@ -9,16 +9,20 @@ import type {
9
9
  WorkerResponse,
10
10
  ChildImpl,
11
11
  } from './types';
12
- import type {IDisposable} from '@parcel/types';
13
- import type {WorkerApi} from './WorkerFarm';
12
+ import type {Async, IDisposable} from '@parcel/types';
13
+ import type {SharedReference, WorkerApi} from './WorkerFarm';
14
14
 
15
15
  import invariant from 'assert';
16
16
  import nullthrows from 'nullthrows';
17
17
  import Logger, {patchConsole, unpatchConsole} from '@parcel/logger';
18
18
  import ThrowableDiagnostic, {anyToDiagnostic} from '@parcel/diagnostic';
19
+ import {deserialize} from '@parcel/core';
19
20
  import bus from './bus';
20
21
  import Profiler from './Profiler';
21
- import Handle from './Handle';
22
+ import _Handle from './Handle';
23
+
24
+ // The import of './Handle' should really be imported eagerly (with @babel/plugin-transform-modules-commonjs's lazy mode).
25
+ const Handle = _Handle;
22
26
 
23
27
  type ChildCall = WorkerRequest & {|
24
28
  resolve: (result: Promise<any> | any) => void,
@@ -30,19 +34,22 @@ export class Child {
30
34
  childId: ?number;
31
35
  maxConcurrentCalls: number = 10;
32
36
  module: ?any;
33
- responseId = 0;
37
+ responseId: number = 0;
34
38
  responseQueue: Map<number, ChildCall> = new Map();
35
39
  loggerDisposable: IDisposable;
36
40
  child: ChildImpl;
37
41
  profiler: ?Profiler;
38
42
  workerApi: WorkerApi;
39
43
  handles: Map<number, Handle> = new Map();
40
- sharedReferences: Map<number, mixed> = new Map();
44
+ sharedReferences: Map<SharedReference, mixed> = new Map();
45
+ sharedReferencesByValue: Map<mixed, SharedReference> = new Map();
41
46
 
42
47
  constructor(ChildBackend: Class<ChildImpl>) {
43
48
  this.child = new ChildBackend(
44
- this.messageListener.bind(this),
45
- this.handleEnd.bind(this),
49
+ m => {
50
+ this.messageListener(m);
51
+ },
52
+ () => this.handleEnd(),
46
53
  );
47
54
 
48
55
  // Monitior all logging events inside this child process and forward to
@@ -52,17 +59,31 @@ export class Child {
52
59
  });
53
60
  }
54
61
 
55
- workerApi = {
62
+ workerApi: {|
63
+ callMaster: (
64
+ request: CallRequest,
65
+ awaitResponse?: ?boolean,
66
+ ) => Promise<mixed>,
67
+ createReverseHandle: (fn: (...args: Array<any>) => mixed) => Handle,
68
+ getSharedReference: (ref: SharedReference) => mixed,
69
+ resolveSharedReference: (value: mixed) => void | SharedReference,
70
+ runHandle: (handle: Handle, args: Array<any>) => Promise<mixed>,
71
+ |} = {
56
72
  callMaster: (
57
73
  request: CallRequest,
58
74
  awaitResponse: ?boolean = true,
59
75
  ): Promise<mixed> => this.addCall(request, awaitResponse),
60
76
  createReverseHandle: (fn: (...args: Array<any>) => mixed): Handle =>
61
77
  this.createReverseHandle(fn),
62
- getSharedReference: (ref: number) => this.sharedReferences.get(ref),
78
+ runHandle: (handle: Handle, args: Array<any>): Promise<mixed> =>
79
+ this.workerApi.callMaster({handle: handle.id, args}, true),
80
+ getSharedReference: (ref: SharedReference) =>
81
+ this.sharedReferences.get(ref),
82
+ resolveSharedReference: (value: mixed) =>
83
+ this.sharedReferencesByValue.get(value),
63
84
  };
64
85
 
65
- messageListener(message: WorkerMessage): void | Promise<void> {
86
+ messageListener(message: WorkerMessage): Async<void> {
66
87
  if (message.type === 'response') {
67
88
  return this.handleResponse(message);
68
89
  } else if (message.type === 'request') {
@@ -74,10 +95,14 @@ export class Child {
74
95
  this.child.send(data);
75
96
  }
76
97
 
77
- childInit(module: string, childId: number): void {
98
+ async childInit(module: string, childId: number): Promise<void> {
78
99
  // $FlowFixMe this must be dynamic
79
100
  this.module = require(module);
80
101
  this.childId = childId;
102
+
103
+ if (this.module.childInit != null) {
104
+ await this.module.childInit();
105
+ }
81
106
  }
82
107
 
83
108
  async handleRequest(data: WorkerRequest): Promise<void> {
@@ -103,7 +128,7 @@ export class Child {
103
128
  let result;
104
129
  if (handleId != null) {
105
130
  try {
106
- let fn = nullthrows(this.handles.get(handleId)).fn;
131
+ let fn = nullthrows(this.handles.get(handleId)?.fn);
107
132
  result = responseFromContent(fn(...args));
108
133
  } catch (e) {
109
134
  result = errorResponseFromError(e);
@@ -111,13 +136,13 @@ export class Child {
111
136
  } else if (method === 'childInit') {
112
137
  try {
113
138
  let [moduleName, childOptions] = args;
114
- if (childOptions.patchConsole) {
139
+ if (childOptions.shouldPatchConsole) {
115
140
  patchConsole();
116
141
  } else {
117
142
  unpatchConsole();
118
143
  }
119
144
 
120
- result = responseFromContent(this.childInit(moduleName, child));
145
+ result = responseFromContent(await this.childInit(moduleName, child));
121
146
  } catch (e) {
122
147
  result = errorResponseFromError(e);
123
148
  }
@@ -135,11 +160,38 @@ export class Child {
135
160
  } catch (e) {
136
161
  result = errorResponseFromError(e);
137
162
  }
163
+ } else if (method === 'takeHeapSnapshot') {
164
+ try {
165
+ let v8 = require('v8');
166
+ result = responseFromContent(
167
+ // $FlowFixMe
168
+ v8.writeHeapSnapshot(
169
+ 'heap-' +
170
+ args[0] +
171
+ '-' +
172
+ (this.childId ? 'worker' + this.childId : 'main') +
173
+ '.heapsnapshot',
174
+ ),
175
+ );
176
+ } catch (e) {
177
+ result = errorResponseFromError(e);
178
+ }
138
179
  } else if (method === 'createSharedReference') {
139
- this.sharedReferences.set(args[0], args[1]);
180
+ let [ref, _value] = args;
181
+ let value =
182
+ _value instanceof ArrayBuffer
183
+ ? // In the case the value is pre-serialized as a buffer,
184
+ // deserialize it.
185
+ deserialize(Buffer.from(_value))
186
+ : _value;
187
+ this.sharedReferences.set(ref, value);
188
+ this.sharedReferencesByValue.set(value, ref);
140
189
  result = responseFromContent(null);
141
190
  } else if (method === 'deleteSharedReference') {
142
- this.sharedReferences.delete(args[0]);
191
+ let ref = args[0];
192
+ let value = this.sharedReferences.get(ref);
193
+ this.sharedReferencesByValue.delete(value);
194
+ this.sharedReferences.delete(ref);
143
195
  result = responseFromContent(null);
144
196
  } else {
145
197
  try {
@@ -152,7 +204,11 @@ export class Child {
152
204
  }
153
205
  }
154
206
 
155
- this.send(result);
207
+ try {
208
+ this.send(result);
209
+ } catch (e) {
210
+ result = this.send(errorResponseFromError(e));
211
+ }
156
212
  }
157
213
 
158
214
  handleResponse(data: WorkerResponse): void {
@@ -184,6 +240,7 @@ export class Child {
184
240
  ...request,
185
241
  type: 'request',
186
242
  child: this.childId,
243
+ // $FlowFixMe Added in Flow 0.121.0 upgrade in #4381
187
244
  awaitResponse,
188
245
  resolve: () => {},
189
246
  reject: () => {},
@@ -236,10 +293,9 @@ export class Child {
236
293
  this.loggerDisposable.dispose();
237
294
  }
238
295
 
239
- createReverseHandle(fn: (...args: Array<any>) => mixed) {
296
+ createReverseHandle(fn: (...args: Array<any>) => mixed): Handle {
240
297
  let handle = new Handle({
241
298
  fn,
242
- workerApi: this.workerApi,
243
299
  childId: this.childId,
244
300
  });
245
301
  this.handles.set(handle.id, handle);
package/src/cpuCount.js CHANGED
@@ -26,6 +26,11 @@ export function detectRealCores(): number {
26
26
  );
27
27
  } else if (platform === 'darwin') {
28
28
  amount = parseInt(exec('sysctl -n hw.physicalcpu_max'), 10);
29
+ } else if (platform === 'win32') {
30
+ const str = exec('wmic cpu get NumberOfCores').match(/\d+/g);
31
+ if (str !== null) {
32
+ amount = parseInt(str.filter(n => n !== '')[0], 10);
33
+ }
29
34
  }
30
35
 
31
36
  if (!amount || amount <= 0) {
@@ -36,9 +41,8 @@ export function detectRealCores(): number {
36
41
  }
37
42
 
38
43
  let cores;
39
- export default function getCores(bypassCache?: boolean = false) {
44
+ export default function getCores(bypassCache?: boolean = false): number {
40
45
  // Do not re-run commands if we already have the count...
41
- // $FlowFixMe
42
46
  if (cores && !bypassCache) {
43
47
  return cores;
44
48
  }
@@ -49,8 +53,9 @@ export default function getCores(bypassCache?: boolean = false) {
49
53
  // Guess the amount of real cores
50
54
  cores = os
51
55
  .cpus()
52
- .filter((cpu, index) => !cpu.model.includes('Intel') || index % 2 === 1)
53
- .length;
56
+ .filter(
57
+ (cpu, index) => !cpu.model.includes('Intel') || index % 2 === 1,
58
+ ).length;
54
59
  }
55
60
 
56
61
  // Another fallback
package/src/index.js CHANGED
@@ -34,4 +34,4 @@ if (!WorkerFarm.isWorker()) {
34
34
  export default WorkerFarm;
35
35
  export {bus};
36
36
  export {Handle} from './WorkerFarm';
37
- export type {WorkerApi, FarmOptions} from './WorkerFarm';
37
+ export type {WorkerApi, FarmOptions, SharedReference} from './WorkerFarm';
@@ -25,7 +25,7 @@ export default class ProcessChild implements ChildImpl {
25
25
  process.on('message', data => this.handleMessage(data));
26
26
  }
27
27
 
28
- handleMessage(data: string) {
28
+ handleMessage(data: string): void {
29
29
  if (data === 'die') {
30
30
  return this.stop();
31
31
  }
@@ -34,7 +34,7 @@ export default class ProcessWorker implements WorkerImpl {
34
34
  this.onExit = onExit;
35
35
  }
36
36
 
37
- start() {
37
+ start(): Promise<void> {
38
38
  this.child = childProcess.fork(WORKER_PATH, process.argv, {
39
39
  execArgv: this.execArgv,
40
40
  env: process.env,
@@ -32,7 +32,7 @@ export default class ThreadsWorker implements WorkerImpl {
32
32
  this.onExit = onExit;
33
33
  }
34
34
 
35
- start() {
35
+ start(): Promise<void> {
36
36
  this.worker = new Worker(WORKER_PATH, {
37
37
  execArgv: this.execArgv,
38
38
  env: process.env,
@@ -47,7 +47,7 @@ export default class ThreadsWorker implements WorkerImpl {
47
47
  });
48
48
  }
49
49
 
50
- stop() {
50
+ stop(): Promise<void> {
51
51
  // In node 12, this returns a promise, but previously it accepted a callback
52
52
  // TODO: Pass a callback in earlier versions of Node
53
53
  return Promise.resolve(this.worker.terminate());
@@ -3,7 +3,7 @@ import os from 'os';
3
3
 
4
4
  import getCores, {detectRealCores} from '../src/cpuCount';
5
5
 
6
- describe('cpuCount', function() {
6
+ describe('cpuCount', function () {
7
7
  it('Should be able to detect real cpu count', () => {
8
8
  // Windows not supported as getting the cpu count takes a couple seconds...
9
9
  if (os.platform() === 'win32') return;