@parcel/workers 2.0.0-nightly.97 → 2.0.0-nightly.970

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,8 +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
- resolveSharedReference(value: mixed): ?number,
56
+ getSharedReference(ref: SharedReference): mixed,
57
+ resolveSharedReference(value: mixed): ?SharedReference,
57
58
  callChild?: (childId: number, request: HandleCallRequest) => Promise<mixed>,
58
59
  |};
59
60
 
@@ -67,13 +68,14 @@ export default class WorkerFarm extends EventEmitter {
67
68
  callQueue: Array<WorkerCall> = [];
68
69
  ending: boolean = false;
69
70
  localWorker: WorkerModule;
71
+ localWorkerInit: ?Promise<void>;
70
72
  options: FarmOptions;
71
73
  run: HandleFunction;
72
74
  warmWorkers: number = 0;
73
75
  workers: Map<number, Worker> = new Map();
74
76
  handles: Map<number, Handle> = new Map();
75
- sharedReferences: Map<number, mixed> = new Map();
76
- sharedReferencesByValue: Map<mixed, number> = new Map();
77
+ sharedReferences: Map<SharedReference, mixed> = new Map();
78
+ sharedReferencesByValue: Map<mixed, SharedReference> = new Map();
77
79
  profiler: ?Profiler;
78
80
 
79
81
  constructor(farmOptions: $Shape<FarmOptions> = {}) {
@@ -94,12 +96,24 @@ export default class WorkerFarm extends EventEmitter {
94
96
 
95
97
  // $FlowFixMe this must be dynamic
96
98
  this.localWorker = require(this.options.workerPath);
99
+ this.localWorkerInit =
100
+ this.localWorker.childInit != null ? this.localWorker.childInit() : null;
97
101
  this.run = this.createHandle('run');
98
102
 
99
103
  this.startMaxWorkers();
100
104
  }
101
105
 
102
- 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
+ |} = {
103
117
  callMaster: async (
104
118
  request: CallRequest,
105
119
  awaitResponse: ?boolean = true,
@@ -122,7 +136,13 @@ export default class WorkerFarm extends EventEmitter {
122
136
  retries: 0,
123
137
  });
124
138
  }),
125
- 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),
126
146
  resolveSharedReference: (value: mixed) =>
127
147
  this.sharedReferencesByValue.get(value),
128
148
  };
@@ -156,7 +176,7 @@ export default class WorkerFarm extends EventEmitter {
156
176
  }
157
177
 
158
178
  createHandle(method: string): HandleFunction {
159
- return (...args) => {
179
+ return async (...args) => {
160
180
  // Child process workers are slow to start (~600ms).
161
181
  // While we're waiting, just run on the main thread.
162
182
  // This significantly speeds up startup time.
@@ -170,15 +190,22 @@ export default class WorkerFarm extends EventEmitter {
170
190
  let processedArgs = restoreDeserializedObject(
171
191
  prepareForSerialization([...args, false]),
172
192
  );
193
+
194
+ if (this.localWorkerInit != null) {
195
+ await this.localWorkerInit;
196
+ this.localWorkerInit = null;
197
+ }
173
198
  return this.localWorker[method](this.workerApi, ...processedArgs);
174
199
  }
175
200
  };
176
201
  }
177
202
 
178
- onError(error: ErrorWithCode, worker: Worker) {
203
+ onError(error: ErrorWithCode, worker: Worker): void | Promise<void> {
179
204
  // Handle ipc errors
180
205
  if (error.code === 'ERR_IPC_CHANNEL_CLOSED') {
181
206
  return this.stopWorker(worker);
207
+ } else {
208
+ logger.error(error, '@parcel/workers');
182
209
  }
183
210
  }
184
211
 
@@ -186,7 +213,8 @@ export default class WorkerFarm extends EventEmitter {
186
213
  let worker = new Worker({
187
214
  forcedKillTime: this.options.forcedKillTime,
188
215
  backend: this.options.backend,
189
- patchConsole: this.options.patchConsole,
216
+ shouldPatchConsole: this.options.shouldPatchConsole,
217
+ sharedReferences: this.sharedReferences,
190
218
  });
191
219
 
192
220
  worker.fork(nullthrows(this.options.workerPath));
@@ -231,7 +259,11 @@ export default class WorkerFarm extends EventEmitter {
231
259
  this.startChild();
232
260
  }
233
261
 
234
- 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) {
235
267
  if (!this.callQueue.length) {
236
268
  break;
237
269
  }
@@ -255,7 +287,7 @@ export default class WorkerFarm extends EventEmitter {
255
287
  let {method, args, location, awaitResponse, idx, handle: handleId} = data;
256
288
  let mod;
257
289
  if (handleId != null) {
258
- mod = nullthrows(this.handles.get(handleId)).fn;
290
+ mod = nullthrows(this.handles.get(handleId)?.fn);
259
291
  } else if (location) {
260
292
  // $FlowFixMe this must be dynamic
261
293
  mod = require(location);
@@ -286,7 +318,6 @@ export default class WorkerFarm extends EventEmitter {
286
318
  }
287
319
  } else {
288
320
  // ESModule default interop
289
- // $FlowFixMe
290
321
  if (mod.__esModule && !mod[method] && mod.default) {
291
322
  mod = mod.default;
292
323
  }
@@ -331,6 +362,10 @@ export default class WorkerFarm extends EventEmitter {
331
362
  async end(): Promise<void> {
332
363
  this.ending = true;
333
364
 
365
+ await Promise.all(
366
+ Array.from(this.workers.values()).map(worker => this.stopWorker(worker)),
367
+ );
368
+
334
369
  for (let handle of this.handles.values()) {
335
370
  handle.dispose();
336
371
  }
@@ -338,9 +373,6 @@ export default class WorkerFarm extends EventEmitter {
338
373
  this.sharedReferences = new Map();
339
374
  this.sharedReferencesByValue = new Map();
340
375
 
341
- await Promise.all(
342
- Array.from(this.workers.values()).map(worker => this.stopWorker(worker)),
343
- );
344
376
  this.ending = false;
345
377
  }
346
378
 
@@ -362,29 +394,28 @@ export default class WorkerFarm extends EventEmitter {
362
394
  );
363
395
  }
364
396
 
365
- createReverseHandle(fn: HandleFunction) {
366
- let handle = new Handle({fn, workerApi: this.workerApi});
397
+ createReverseHandle(fn: HandleFunction): Handle {
398
+ let handle = new Handle({fn});
367
399
  this.handles.set(handle.id, handle);
368
400
  return handle;
369
401
  }
370
402
 
371
- 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>|}> {
372
409
  let ref = referenceId++;
373
410
  this.sharedReferences.set(ref, value);
374
411
  this.sharedReferencesByValue.set(value, ref);
412
+
413
+ let toSend = buffer ? buffer.buffer : value;
375
414
  let promises = [];
376
415
  for (let worker of this.workers.values()) {
377
- promises.push(
378
- new Promise((resolve, reject) => {
379
- worker.call({
380
- method: 'createSharedReference',
381
- args: [ref, value],
382
- resolve,
383
- reject,
384
- retries: 0,
385
- });
386
- }),
387
- );
416
+ if (worker.ready) {
417
+ promises.push(worker.sendSharedReference(ref, toSend));
418
+ }
388
419
  }
389
420
 
390
421
  await Promise.all(promises);
@@ -403,6 +434,7 @@ export default class WorkerFarm extends EventEmitter {
403
434
  args: [ref],
404
435
  resolve,
405
436
  reject,
437
+ skipReadyCheck: true,
406
438
  retries: 0,
407
439
  });
408
440
  }),
@@ -424,6 +456,7 @@ export default class WorkerFarm extends EventEmitter {
424
456
  resolve,
425
457
  reject,
426
458
  retries: 0,
459
+ skipReadyCheck: true,
427
460
  });
428
461
  }),
429
462
  );
@@ -453,6 +486,7 @@ export default class WorkerFarm extends EventEmitter {
453
486
  resolve,
454
487
  reject,
455
488
  retries: 0,
489
+ skipReadyCheck: true,
456
490
  });
457
491
  }),
458
492
  );
@@ -460,7 +494,7 @@ export default class WorkerFarm extends EventEmitter {
460
494
 
461
495
  var profiles = await Promise.all(promises);
462
496
  let trace = new Trace();
463
- let filename = `profile-${profileId++}.trace`;
497
+ let filename = `profile-${getTimeId()}.trace`;
464
498
  let stream = trace.pipe(fs.createWriteStream(filename));
465
499
 
466
500
  for (let profile of profiles) {
@@ -474,21 +508,84 @@ export default class WorkerFarm extends EventEmitter {
474
508
 
475
509
  logger.info({
476
510
  origin: '@parcel/workers',
477
- message: `Wrote profile to ${filename}`,
511
+ message: md`Wrote profile to ${filename}`,
478
512
  });
479
513
  }
480
514
 
481
- 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 {
482
570
  return process.env.PARCEL_WORKERS
483
571
  ? parseInt(process.env.PARCEL_WORKERS, 10)
484
- : cpuCount();
572
+ : Math.ceil(cpuCount() / 2);
485
573
  }
486
574
 
487
- static isWorker() {
575
+ static isWorker(): boolean {
488
576
  return !!child;
489
577
  }
490
578
 
491
- 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
+ |} {
492
589
  invariant(
493
590
  child != null,
494
591
  'WorkerFarm.getWorkerApi can only be called within workers',
@@ -496,7 +593,20 @@ export default class WorkerFarm extends EventEmitter {
496
593
  return child.workerApi;
497
594
  }
498
595
 
499
- static getConcurrentCallsPerWorker() {
500
- 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;
501
598
  }
502
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,20 +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();
41
- sharedReferencesByValue: Map<mixed, number> = new Map();
44
+ sharedReferences: Map<SharedReference, mixed> = new Map();
45
+ sharedReferencesByValue: Map<mixed, SharedReference> = new Map();
42
46
 
43
47
  constructor(ChildBackend: Class<ChildImpl>) {
44
48
  this.child = new ChildBackend(
45
- this.messageListener.bind(this),
46
- this.handleEnd.bind(this),
49
+ m => {
50
+ this.messageListener(m);
51
+ },
52
+ () => this.handleEnd(),
47
53
  );
48
54
 
49
55
  // Monitior all logging events inside this child process and forward to
@@ -53,19 +59,31 @@ export class Child {
53
59
  });
54
60
  }
55
61
 
56
- 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
+ |} = {
57
72
  callMaster: (
58
73
  request: CallRequest,
59
74
  awaitResponse: ?boolean = true,
60
75
  ): Promise<mixed> => this.addCall(request, awaitResponse),
61
76
  createReverseHandle: (fn: (...args: Array<any>) => mixed): Handle =>
62
77
  this.createReverseHandle(fn),
63
- 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),
64
82
  resolveSharedReference: (value: mixed) =>
65
83
  this.sharedReferencesByValue.get(value),
66
84
  };
67
85
 
68
- messageListener(message: WorkerMessage): void | Promise<void> {
86
+ messageListener(message: WorkerMessage): Async<void> {
69
87
  if (message.type === 'response') {
70
88
  return this.handleResponse(message);
71
89
  } else if (message.type === 'request') {
@@ -77,10 +95,14 @@ export class Child {
77
95
  this.child.send(data);
78
96
  }
79
97
 
80
- childInit(module: string, childId: number): void {
98
+ async childInit(module: string, childId: number): Promise<void> {
81
99
  // $FlowFixMe this must be dynamic
82
100
  this.module = require(module);
83
101
  this.childId = childId;
102
+
103
+ if (this.module.childInit != null) {
104
+ await this.module.childInit();
105
+ }
84
106
  }
85
107
 
86
108
  async handleRequest(data: WorkerRequest): Promise<void> {
@@ -106,7 +128,7 @@ export class Child {
106
128
  let result;
107
129
  if (handleId != null) {
108
130
  try {
109
- let fn = nullthrows(this.handles.get(handleId)).fn;
131
+ let fn = nullthrows(this.handles.get(handleId)?.fn);
110
132
  result = responseFromContent(fn(...args));
111
133
  } catch (e) {
112
134
  result = errorResponseFromError(e);
@@ -114,13 +136,13 @@ export class Child {
114
136
  } else if (method === 'childInit') {
115
137
  try {
116
138
  let [moduleName, childOptions] = args;
117
- if (childOptions.patchConsole) {
139
+ if (childOptions.shouldPatchConsole) {
118
140
  patchConsole();
119
141
  } else {
120
142
  unpatchConsole();
121
143
  }
122
144
 
123
- result = responseFromContent(this.childInit(moduleName, child));
145
+ result = responseFromContent(await this.childInit(moduleName, child));
124
146
  } catch (e) {
125
147
  result = errorResponseFromError(e);
126
148
  }
@@ -138,13 +160,38 @@ export class Child {
138
160
  } catch (e) {
139
161
  result = errorResponseFromError(e);
140
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
+ }
141
179
  } else if (method === 'createSharedReference') {
142
- let [ref, value] = args;
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;
143
187
  this.sharedReferences.set(ref, value);
144
188
  this.sharedReferencesByValue.set(value, ref);
145
189
  result = responseFromContent(null);
146
190
  } else if (method === 'deleteSharedReference') {
147
- 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);
148
195
  result = responseFromContent(null);
149
196
  } else {
150
197
  try {
@@ -157,7 +204,11 @@ export class Child {
157
204
  }
158
205
  }
159
206
 
160
- this.send(result);
207
+ try {
208
+ this.send(result);
209
+ } catch (e) {
210
+ result = this.send(errorResponseFromError(e));
211
+ }
161
212
  }
162
213
 
163
214
  handleResponse(data: WorkerResponse): void {
@@ -189,6 +240,7 @@ export class Child {
189
240
  ...request,
190
241
  type: 'request',
191
242
  child: this.childId,
243
+ // $FlowFixMe Added in Flow 0.121.0 upgrade in #4381
192
244
  awaitResponse,
193
245
  resolve: () => {},
194
246
  reject: () => {},
@@ -241,10 +293,9 @@ export class Child {
241
293
  this.loggerDisposable.dispose();
242
294
  }
243
295
 
244
- createReverseHandle(fn: (...args: Array<any>) => mixed) {
296
+ createReverseHandle(fn: (...args: Array<any>) => mixed): Handle {
245
297
  let handle = new Handle({
246
298
  fn,
247
- workerApi: this.workerApi,
248
299
  childId: this.childId,
249
300
  });
250
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;
@@ -1,4 +1,4 @@
1
- const WorkerFarm = require('../../../').default;
1
+ const WorkerFarm = require('../../../src/WorkerFarm').default;
2
2
 
3
3
  function run() {
4
4
  if (WorkerFarm.isWorker()) {