@parcel/workers 2.0.0-nightly.121 → 2.0.0-nightly.1211
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +22 -0
- package/lib/Handle.js +14 -45
- package/lib/Profiler.js +20 -10
- package/lib/Trace.js +16 -11
- package/lib/Worker.js +97 -26
- package/lib/WorkerFarm.js +237 -101
- package/lib/bus.js +10 -2
- package/lib/child.js +113 -63
- package/lib/childState.js +1 -1
- package/lib/cpuCount.js +28 -7
- package/lib/index.js +26 -10
- package/lib/process/ProcessChild.js +22 -11
- package/lib/process/ProcessWorker.js +30 -19
- package/lib/threads/ThreadsChild.js +32 -14
- package/lib/threads/ThreadsWorker.js +28 -16
- package/package.json +18 -7
- package/src/Handle.js +10 -39
- package/src/Profiler.js +1 -1
- package/src/Trace.js +8 -4
- package/src/Worker.js +75 -11
- package/src/WorkerFarm.js +195 -50
- package/src/bus.js +1 -1
- package/src/child.js +70 -21
- package/src/cpuCount.js +9 -4
- package/src/index.js +1 -1
- package/src/process/ProcessChild.js +2 -1
- package/src/process/ProcessWorker.js +1 -1
- package/src/threads/ThreadsWorker.js +2 -2
- package/test/cpuCount.test.js +1 -1
- package/test/integration/workerfarm/console.js +1 -1
- package/test/integration/workerfarm/logging.js +1 -1
- package/test/integration/workerfarm/reverse-handle.js +2 -2
- package/test/workerfarm.js +5 -5
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
|
-
|
|
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:
|
|
56
|
-
resolveSharedReference(value: mixed): ?
|
|
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,15 @@ 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<
|
|
76
|
-
sharedReferencesByValue: Map<mixed,
|
|
77
|
+
sharedReferences: Map<SharedReference, mixed> = new Map();
|
|
78
|
+
sharedReferencesByValue: Map<mixed, SharedReference> = new Map();
|
|
79
|
+
serializedSharedReferences: Map<SharedReference, ?ArrayBuffer> = new Map();
|
|
77
80
|
profiler: ?Profiler;
|
|
78
81
|
|
|
79
82
|
constructor(farmOptions: $Shape<FarmOptions> = {}) {
|
|
@@ -94,12 +97,24 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
94
97
|
|
|
95
98
|
// $FlowFixMe this must be dynamic
|
|
96
99
|
this.localWorker = require(this.options.workerPath);
|
|
100
|
+
this.localWorkerInit =
|
|
101
|
+
this.localWorker.childInit != null ? this.localWorker.childInit() : null;
|
|
97
102
|
this.run = this.createHandle('run');
|
|
98
103
|
|
|
99
104
|
this.startMaxWorkers();
|
|
100
105
|
}
|
|
101
106
|
|
|
102
|
-
workerApi
|
|
107
|
+
workerApi: {|
|
|
108
|
+
callChild: (childId: number, request: HandleCallRequest) => Promise<mixed>,
|
|
109
|
+
callMaster: (
|
|
110
|
+
request: CallRequest,
|
|
111
|
+
awaitResponse?: ?boolean,
|
|
112
|
+
) => Promise<mixed>,
|
|
113
|
+
createReverseHandle: (fn: HandleFunction) => Handle,
|
|
114
|
+
getSharedReference: (ref: SharedReference) => mixed,
|
|
115
|
+
resolveSharedReference: (value: mixed) => void | SharedReference,
|
|
116
|
+
runHandle: (handle: Handle, args: Array<any>) => Promise<mixed>,
|
|
117
|
+
|} = {
|
|
103
118
|
callMaster: async (
|
|
104
119
|
request: CallRequest,
|
|
105
120
|
awaitResponse: ?boolean = true,
|
|
@@ -122,7 +137,13 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
122
137
|
retries: 0,
|
|
123
138
|
});
|
|
124
139
|
}),
|
|
125
|
-
|
|
140
|
+
runHandle: (handle: Handle, args: Array<any>): Promise<mixed> =>
|
|
141
|
+
this.workerApi.callChild(nullthrows(handle.childId), {
|
|
142
|
+
handle: handle.id,
|
|
143
|
+
args,
|
|
144
|
+
}),
|
|
145
|
+
getSharedReference: (ref: SharedReference) =>
|
|
146
|
+
this.sharedReferences.get(ref),
|
|
126
147
|
resolveSharedReference: (value: mixed) =>
|
|
127
148
|
this.sharedReferencesByValue.get(value),
|
|
128
149
|
};
|
|
@@ -155,30 +176,42 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
155
176
|
);
|
|
156
177
|
}
|
|
157
178
|
|
|
158
|
-
createHandle(method: string): HandleFunction {
|
|
159
|
-
return (...args) => {
|
|
179
|
+
createHandle(method: string, useMainThread: boolean = false): HandleFunction {
|
|
180
|
+
return async (...args) => {
|
|
160
181
|
// Child process workers are slow to start (~600ms).
|
|
161
182
|
// While we're waiting, just run on the main thread.
|
|
162
183
|
// This significantly speeds up startup time.
|
|
163
|
-
if (this.shouldUseRemoteWorkers()) {
|
|
184
|
+
if (this.shouldUseRemoteWorkers() && !useMainThread) {
|
|
164
185
|
return this.addCall(method, [...args, false]);
|
|
165
186
|
} else {
|
|
166
187
|
if (this.options.warmWorkers && this.shouldStartRemoteWorkers()) {
|
|
167
188
|
this.warmupWorker(method, args);
|
|
168
189
|
}
|
|
169
190
|
|
|
170
|
-
let processedArgs
|
|
171
|
-
|
|
172
|
-
|
|
191
|
+
let processedArgs;
|
|
192
|
+
if (!useMainThread) {
|
|
193
|
+
processedArgs = restoreDeserializedObject(
|
|
194
|
+
prepareForSerialization([...args, false]),
|
|
195
|
+
);
|
|
196
|
+
} else {
|
|
197
|
+
processedArgs = args;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (this.localWorkerInit != null) {
|
|
201
|
+
await this.localWorkerInit;
|
|
202
|
+
this.localWorkerInit = null;
|
|
203
|
+
}
|
|
173
204
|
return this.localWorker[method](this.workerApi, ...processedArgs);
|
|
174
205
|
}
|
|
175
206
|
};
|
|
176
207
|
}
|
|
177
208
|
|
|
178
|
-
onError(error: ErrorWithCode, worker: Worker) {
|
|
209
|
+
onError(error: ErrorWithCode, worker: Worker): void | Promise<void> {
|
|
179
210
|
// Handle ipc errors
|
|
180
211
|
if (error.code === 'ERR_IPC_CHANNEL_CLOSED') {
|
|
181
212
|
return this.stopWorker(worker);
|
|
213
|
+
} else {
|
|
214
|
+
logger.error(error, '@parcel/workers');
|
|
182
215
|
}
|
|
183
216
|
}
|
|
184
217
|
|
|
@@ -186,7 +219,8 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
186
219
|
let worker = new Worker({
|
|
187
220
|
forcedKillTime: this.options.forcedKillTime,
|
|
188
221
|
backend: this.options.backend,
|
|
189
|
-
|
|
222
|
+
shouldPatchConsole: this.options.shouldPatchConsole,
|
|
223
|
+
sharedReferences: this.sharedReferences,
|
|
190
224
|
});
|
|
191
225
|
|
|
192
226
|
worker.fork(nullthrows(this.options.workerPath));
|
|
@@ -231,7 +265,11 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
231
265
|
this.startChild();
|
|
232
266
|
}
|
|
233
267
|
|
|
234
|
-
|
|
268
|
+
let workers = [...this.workers.values()].sort(
|
|
269
|
+
(a, b) => a.calls.size - b.calls.size,
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
for (let worker of workers) {
|
|
235
273
|
if (!this.callQueue.length) {
|
|
236
274
|
break;
|
|
237
275
|
}
|
|
@@ -241,9 +279,22 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
241
279
|
}
|
|
242
280
|
|
|
243
281
|
if (worker.calls.size < this.options.maxConcurrentCallsPerWorker) {
|
|
244
|
-
|
|
282
|
+
this.callWorker(worker, this.callQueue.shift());
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async callWorker(worker: Worker, call: WorkerCall): Promise<void> {
|
|
288
|
+
for (let ref of this.sharedReferences.keys()) {
|
|
289
|
+
if (!worker.sentSharedReferences.has(ref)) {
|
|
290
|
+
await worker.sendSharedReference(
|
|
291
|
+
ref,
|
|
292
|
+
this.getSerializedSharedReference(ref),
|
|
293
|
+
);
|
|
245
294
|
}
|
|
246
295
|
}
|
|
296
|
+
|
|
297
|
+
worker.call(call);
|
|
247
298
|
}
|
|
248
299
|
|
|
249
300
|
async processRequest(
|
|
@@ -255,7 +306,7 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
255
306
|
let {method, args, location, awaitResponse, idx, handle: handleId} = data;
|
|
256
307
|
let mod;
|
|
257
308
|
if (handleId != null) {
|
|
258
|
-
mod = nullthrows(this.handles.get(handleId))
|
|
309
|
+
mod = nullthrows(this.handles.get(handleId)?.fn);
|
|
259
310
|
} else if (location) {
|
|
260
311
|
// $FlowFixMe this must be dynamic
|
|
261
312
|
mod = require(location);
|
|
@@ -286,7 +337,6 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
286
337
|
}
|
|
287
338
|
} else {
|
|
288
339
|
// ESModule default interop
|
|
289
|
-
// $FlowFixMe
|
|
290
340
|
if (mod.__esModule && !mod[method] && mod.default) {
|
|
291
341
|
mod = mod.default;
|
|
292
342
|
}
|
|
@@ -331,6 +381,10 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
331
381
|
async end(): Promise<void> {
|
|
332
382
|
this.ending = true;
|
|
333
383
|
|
|
384
|
+
await Promise.all(
|
|
385
|
+
Array.from(this.workers.values()).map(worker => this.stopWorker(worker)),
|
|
386
|
+
);
|
|
387
|
+
|
|
334
388
|
for (let handle of this.handles.values()) {
|
|
335
389
|
handle.dispose();
|
|
336
390
|
}
|
|
@@ -338,9 +392,6 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
338
392
|
this.sharedReferences = new Map();
|
|
339
393
|
this.sharedReferencesByValue = new Map();
|
|
340
394
|
|
|
341
|
-
await Promise.all(
|
|
342
|
-
Array.from(this.workers.values()).map(worker => this.stopWorker(worker)),
|
|
343
|
-
);
|
|
344
395
|
this.ending = false;
|
|
345
396
|
}
|
|
346
397
|
|
|
@@ -362,40 +413,37 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
362
413
|
);
|
|
363
414
|
}
|
|
364
415
|
|
|
365
|
-
createReverseHandle(fn: HandleFunction) {
|
|
366
|
-
let handle = new Handle({fn
|
|
416
|
+
createReverseHandle(fn: HandleFunction): Handle {
|
|
417
|
+
let handle = new Handle({fn});
|
|
367
418
|
this.handles.set(handle.id, handle);
|
|
368
419
|
return handle;
|
|
369
420
|
}
|
|
370
421
|
|
|
371
|
-
|
|
422
|
+
createSharedReference(
|
|
423
|
+
value: mixed,
|
|
424
|
+
isCacheable: boolean = true,
|
|
425
|
+
): {|ref: SharedReference, dispose(): Promise<mixed>|} {
|
|
372
426
|
let ref = referenceId++;
|
|
373
427
|
this.sharedReferences.set(ref, value);
|
|
374
428
|
this.sharedReferencesByValue.set(value, ref);
|
|
375
|
-
|
|
376
|
-
|
|
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
|
-
);
|
|
429
|
+
if (!isCacheable) {
|
|
430
|
+
this.serializedSharedReferences.set(ref, null);
|
|
388
431
|
}
|
|
389
432
|
|
|
390
|
-
await Promise.all(promises);
|
|
391
|
-
|
|
392
433
|
return {
|
|
393
434
|
ref,
|
|
394
435
|
dispose: () => {
|
|
395
436
|
this.sharedReferences.delete(ref);
|
|
396
437
|
this.sharedReferencesByValue.delete(value);
|
|
438
|
+
this.serializedSharedReferences.delete(ref);
|
|
439
|
+
|
|
397
440
|
let promises = [];
|
|
398
441
|
for (let worker of this.workers.values()) {
|
|
442
|
+
if (!worker.sentSharedReferences.has(ref)) {
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
worker.sentSharedReferences.delete(ref);
|
|
399
447
|
promises.push(
|
|
400
448
|
new Promise((resolve, reject) => {
|
|
401
449
|
worker.call({
|
|
@@ -403,6 +451,7 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
403
451
|
args: [ref],
|
|
404
452
|
resolve,
|
|
405
453
|
reject,
|
|
454
|
+
skipReadyCheck: true,
|
|
406
455
|
retries: 0,
|
|
407
456
|
});
|
|
408
457
|
}),
|
|
@@ -413,6 +462,24 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
413
462
|
};
|
|
414
463
|
}
|
|
415
464
|
|
|
465
|
+
getSerializedSharedReference(ref: SharedReference): ArrayBuffer {
|
|
466
|
+
let cached = this.serializedSharedReferences.get(ref);
|
|
467
|
+
if (cached) {
|
|
468
|
+
return cached;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
let value = this.sharedReferences.get(ref);
|
|
472
|
+
let buf = serialize(value).buffer;
|
|
473
|
+
|
|
474
|
+
// If the reference was created with the isCacheable option set to false,
|
|
475
|
+
// serializedSharedReferences will contain `null` as the value.
|
|
476
|
+
if (cached !== null) {
|
|
477
|
+
this.serializedSharedReferences.set(ref, buf);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return buf;
|
|
481
|
+
}
|
|
482
|
+
|
|
416
483
|
async startProfile() {
|
|
417
484
|
let promises = [];
|
|
418
485
|
for (let worker of this.workers.values()) {
|
|
@@ -424,6 +491,7 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
424
491
|
resolve,
|
|
425
492
|
reject,
|
|
426
493
|
retries: 0,
|
|
494
|
+
skipReadyCheck: true,
|
|
427
495
|
});
|
|
428
496
|
}),
|
|
429
497
|
);
|
|
@@ -453,6 +521,7 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
453
521
|
resolve,
|
|
454
522
|
reject,
|
|
455
523
|
retries: 0,
|
|
524
|
+
skipReadyCheck: true,
|
|
456
525
|
});
|
|
457
526
|
}),
|
|
458
527
|
);
|
|
@@ -460,7 +529,7 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
460
529
|
|
|
461
530
|
var profiles = await Promise.all(promises);
|
|
462
531
|
let trace = new Trace();
|
|
463
|
-
let filename = `profile-${
|
|
532
|
+
let filename = `profile-${getTimeId()}.trace`;
|
|
464
533
|
let stream = trace.pipe(fs.createWriteStream(filename));
|
|
465
534
|
|
|
466
535
|
for (let profile of profiles) {
|
|
@@ -474,21 +543,84 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
474
543
|
|
|
475
544
|
logger.info({
|
|
476
545
|
origin: '@parcel/workers',
|
|
477
|
-
message: `Wrote profile to ${filename}`,
|
|
546
|
+
message: md`Wrote profile to ${filename}`,
|
|
478
547
|
});
|
|
479
548
|
}
|
|
480
549
|
|
|
481
|
-
|
|
550
|
+
async callAllWorkers(method: string, args: Array<any>) {
|
|
551
|
+
let promises = [];
|
|
552
|
+
for (let worker of this.workers.values()) {
|
|
553
|
+
promises.push(
|
|
554
|
+
new Promise((resolve, reject) => {
|
|
555
|
+
worker.call({
|
|
556
|
+
method,
|
|
557
|
+
args,
|
|
558
|
+
resolve,
|
|
559
|
+
reject,
|
|
560
|
+
retries: 0,
|
|
561
|
+
});
|
|
562
|
+
}),
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
promises.push(this.localWorker[method](this.workerApi, ...args));
|
|
567
|
+
await Promise.all(promises);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
async takeHeapSnapshot() {
|
|
571
|
+
let snapshotId = getTimeId();
|
|
572
|
+
|
|
573
|
+
try {
|
|
574
|
+
let snapshotPaths = await Promise.all(
|
|
575
|
+
[...this.workers.values()].map(
|
|
576
|
+
worker =>
|
|
577
|
+
new Promise((resolve, reject) => {
|
|
578
|
+
worker.call({
|
|
579
|
+
method: 'takeHeapSnapshot',
|
|
580
|
+
args: [snapshotId],
|
|
581
|
+
resolve,
|
|
582
|
+
reject,
|
|
583
|
+
retries: 0,
|
|
584
|
+
skipReadyCheck: true,
|
|
585
|
+
});
|
|
586
|
+
}),
|
|
587
|
+
),
|
|
588
|
+
);
|
|
589
|
+
|
|
590
|
+
logger.info({
|
|
591
|
+
origin: '@parcel/workers',
|
|
592
|
+
message: md`Wrote heap snapshots to the following paths:\n${snapshotPaths.join(
|
|
593
|
+
'\n',
|
|
594
|
+
)}`,
|
|
595
|
+
});
|
|
596
|
+
} catch {
|
|
597
|
+
logger.error({
|
|
598
|
+
origin: '@parcel/workers',
|
|
599
|
+
message: 'Unable to take heap snapshots. Note: requires Node 11.13.0+',
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
static getNumWorkers(): number {
|
|
482
605
|
return process.env.PARCEL_WORKERS
|
|
483
606
|
? parseInt(process.env.PARCEL_WORKERS, 10)
|
|
484
|
-
: cpuCount();
|
|
607
|
+
: Math.ceil(cpuCount() / 2);
|
|
485
608
|
}
|
|
486
609
|
|
|
487
|
-
static isWorker() {
|
|
610
|
+
static isWorker(): boolean {
|
|
488
611
|
return !!child;
|
|
489
612
|
}
|
|
490
613
|
|
|
491
|
-
static getWorkerApi() {
|
|
614
|
+
static getWorkerApi(): {|
|
|
615
|
+
callMaster: (
|
|
616
|
+
request: CallRequest,
|
|
617
|
+
awaitResponse?: ?boolean,
|
|
618
|
+
) => Promise<mixed>,
|
|
619
|
+
createReverseHandle: (fn: (...args: Array<any>) => mixed) => Handle,
|
|
620
|
+
getSharedReference: (ref: SharedReference) => mixed,
|
|
621
|
+
resolveSharedReference: (value: mixed) => void | SharedReference,
|
|
622
|
+
runHandle: (handle: Handle, args: Array<any>) => Promise<mixed>,
|
|
623
|
+
|} {
|
|
492
624
|
invariant(
|
|
493
625
|
child != null,
|
|
494
626
|
'WorkerFarm.getWorkerApi can only be called within workers',
|
|
@@ -496,7 +628,20 @@ export default class WorkerFarm extends EventEmitter {
|
|
|
496
628
|
return child.workerApi;
|
|
497
629
|
}
|
|
498
630
|
|
|
499
|
-
static getConcurrentCallsPerWorker() {
|
|
500
|
-
return parseInt(process.env.PARCEL_MAX_CONCURRENT_CALLS, 10) ||
|
|
631
|
+
static getConcurrentCallsPerWorker(): number {
|
|
632
|
+
return parseInt(process.env.PARCEL_MAX_CONCURRENT_CALLS, 10) || 30;
|
|
501
633
|
}
|
|
502
634
|
}
|
|
635
|
+
|
|
636
|
+
function getTimeId() {
|
|
637
|
+
let now = new Date();
|
|
638
|
+
return (
|
|
639
|
+
String(now.getFullYear()) +
|
|
640
|
+
String(now.getMonth() + 1).padStart(2, '0') +
|
|
641
|
+
String(now.getDate()).padStart(2, '0') +
|
|
642
|
+
'-' +
|
|
643
|
+
String(now.getHours()).padStart(2, '0') +
|
|
644
|
+
String(now.getMinutes()).padStart(2, '0') +
|
|
645
|
+
String(now.getSeconds()).padStart(2, '0')
|
|
646
|
+
);
|
|
647
|
+
}
|
package/src/bus.js
CHANGED
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 {
|
|
12
|
+
import type {Async, IDisposable} from '@parcel/types';
|
|
13
|
+
import type {SharedReference} 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
|
|
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,21 @@ 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
|
-
workerApi: WorkerApi;
|
|
39
42
|
handles: Map<number, Handle> = new Map();
|
|
40
|
-
sharedReferences: Map<
|
|
41
|
-
sharedReferencesByValue: Map<mixed,
|
|
43
|
+
sharedReferences: Map<SharedReference, mixed> = new Map();
|
|
44
|
+
sharedReferencesByValue: Map<mixed, SharedReference> = new Map();
|
|
42
45
|
|
|
43
46
|
constructor(ChildBackend: Class<ChildImpl>) {
|
|
44
47
|
this.child = new ChildBackend(
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
m => {
|
|
49
|
+
this.messageListener(m);
|
|
50
|
+
},
|
|
51
|
+
() => this.handleEnd(),
|
|
47
52
|
);
|
|
48
53
|
|
|
49
54
|
// Monitior all logging events inside this child process and forward to
|
|
@@ -53,19 +58,31 @@ export class Child {
|
|
|
53
58
|
});
|
|
54
59
|
}
|
|
55
60
|
|
|
56
|
-
workerApi
|
|
61
|
+
workerApi: {|
|
|
62
|
+
callMaster: (
|
|
63
|
+
request: CallRequest,
|
|
64
|
+
awaitResponse?: ?boolean,
|
|
65
|
+
) => Promise<mixed>,
|
|
66
|
+
createReverseHandle: (fn: (...args: Array<any>) => mixed) => Handle,
|
|
67
|
+
getSharedReference: (ref: SharedReference) => mixed,
|
|
68
|
+
resolveSharedReference: (value: mixed) => void | SharedReference,
|
|
69
|
+
runHandle: (handle: Handle, args: Array<any>) => Promise<mixed>,
|
|
70
|
+
|} = {
|
|
57
71
|
callMaster: (
|
|
58
72
|
request: CallRequest,
|
|
59
73
|
awaitResponse: ?boolean = true,
|
|
60
74
|
): Promise<mixed> => this.addCall(request, awaitResponse),
|
|
61
75
|
createReverseHandle: (fn: (...args: Array<any>) => mixed): Handle =>
|
|
62
76
|
this.createReverseHandle(fn),
|
|
63
|
-
|
|
77
|
+
runHandle: (handle: Handle, args: Array<any>): Promise<mixed> =>
|
|
78
|
+
this.workerApi.callMaster({handle: handle.id, args}, true),
|
|
79
|
+
getSharedReference: (ref: SharedReference) =>
|
|
80
|
+
this.sharedReferences.get(ref),
|
|
64
81
|
resolveSharedReference: (value: mixed) =>
|
|
65
82
|
this.sharedReferencesByValue.get(value),
|
|
66
83
|
};
|
|
67
84
|
|
|
68
|
-
messageListener(message: WorkerMessage):
|
|
85
|
+
messageListener(message: WorkerMessage): Async<void> {
|
|
69
86
|
if (message.type === 'response') {
|
|
70
87
|
return this.handleResponse(message);
|
|
71
88
|
} else if (message.type === 'request') {
|
|
@@ -77,10 +94,14 @@ export class Child {
|
|
|
77
94
|
this.child.send(data);
|
|
78
95
|
}
|
|
79
96
|
|
|
80
|
-
childInit(module: string, childId: number): void {
|
|
97
|
+
async childInit(module: string, childId: number): Promise<void> {
|
|
81
98
|
// $FlowFixMe this must be dynamic
|
|
82
99
|
this.module = require(module);
|
|
83
100
|
this.childId = childId;
|
|
101
|
+
|
|
102
|
+
if (this.module.childInit != null) {
|
|
103
|
+
await this.module.childInit();
|
|
104
|
+
}
|
|
84
105
|
}
|
|
85
106
|
|
|
86
107
|
async handleRequest(data: WorkerRequest): Promise<void> {
|
|
@@ -106,7 +127,7 @@ export class Child {
|
|
|
106
127
|
let result;
|
|
107
128
|
if (handleId != null) {
|
|
108
129
|
try {
|
|
109
|
-
let fn = nullthrows(this.handles.get(handleId))
|
|
130
|
+
let fn = nullthrows(this.handles.get(handleId)?.fn);
|
|
110
131
|
result = responseFromContent(fn(...args));
|
|
111
132
|
} catch (e) {
|
|
112
133
|
result = errorResponseFromError(e);
|
|
@@ -114,13 +135,13 @@ export class Child {
|
|
|
114
135
|
} else if (method === 'childInit') {
|
|
115
136
|
try {
|
|
116
137
|
let [moduleName, childOptions] = args;
|
|
117
|
-
if (childOptions.
|
|
138
|
+
if (childOptions.shouldPatchConsole) {
|
|
118
139
|
patchConsole();
|
|
119
140
|
} else {
|
|
120
141
|
unpatchConsole();
|
|
121
142
|
}
|
|
122
143
|
|
|
123
|
-
result = responseFromContent(this.childInit(moduleName, child));
|
|
144
|
+
result = responseFromContent(await this.childInit(moduleName, child));
|
|
124
145
|
} catch (e) {
|
|
125
146
|
result = errorResponseFromError(e);
|
|
126
147
|
}
|
|
@@ -138,13 +159,37 @@ export class Child {
|
|
|
138
159
|
} catch (e) {
|
|
139
160
|
result = errorResponseFromError(e);
|
|
140
161
|
}
|
|
162
|
+
} else if (method === 'takeHeapSnapshot') {
|
|
163
|
+
try {
|
|
164
|
+
let v8 = require('v8');
|
|
165
|
+
result = responseFromContent(
|
|
166
|
+
v8.writeHeapSnapshot(
|
|
167
|
+
'heap-' +
|
|
168
|
+
args[0] +
|
|
169
|
+
'-' +
|
|
170
|
+
(this.childId ? 'worker' + this.childId : 'main') +
|
|
171
|
+
'.heapsnapshot',
|
|
172
|
+
),
|
|
173
|
+
);
|
|
174
|
+
} catch (e) {
|
|
175
|
+
result = errorResponseFromError(e);
|
|
176
|
+
}
|
|
141
177
|
} else if (method === 'createSharedReference') {
|
|
142
|
-
let [ref,
|
|
178
|
+
let [ref, _value] = args;
|
|
179
|
+
let value =
|
|
180
|
+
_value instanceof ArrayBuffer
|
|
181
|
+
? // In the case the value is pre-serialized as a buffer,
|
|
182
|
+
// deserialize it.
|
|
183
|
+
deserialize(Buffer.from(_value))
|
|
184
|
+
: _value;
|
|
143
185
|
this.sharedReferences.set(ref, value);
|
|
144
186
|
this.sharedReferencesByValue.set(value, ref);
|
|
145
187
|
result = responseFromContent(null);
|
|
146
188
|
} else if (method === 'deleteSharedReference') {
|
|
147
|
-
|
|
189
|
+
let ref = args[0];
|
|
190
|
+
let value = this.sharedReferences.get(ref);
|
|
191
|
+
this.sharedReferencesByValue.delete(value);
|
|
192
|
+
this.sharedReferences.delete(ref);
|
|
148
193
|
result = responseFromContent(null);
|
|
149
194
|
} else {
|
|
150
195
|
try {
|
|
@@ -157,7 +202,11 @@ export class Child {
|
|
|
157
202
|
}
|
|
158
203
|
}
|
|
159
204
|
|
|
160
|
-
|
|
205
|
+
try {
|
|
206
|
+
this.send(result);
|
|
207
|
+
} catch (e) {
|
|
208
|
+
result = this.send(errorResponseFromError(e));
|
|
209
|
+
}
|
|
161
210
|
}
|
|
162
211
|
|
|
163
212
|
handleResponse(data: WorkerResponse): void {
|
|
@@ -189,6 +238,7 @@ export class Child {
|
|
|
189
238
|
...request,
|
|
190
239
|
type: 'request',
|
|
191
240
|
child: this.childId,
|
|
241
|
+
// $FlowFixMe Added in Flow 0.121.0 upgrade in #4381
|
|
192
242
|
awaitResponse,
|
|
193
243
|
resolve: () => {},
|
|
194
244
|
reject: () => {},
|
|
@@ -241,10 +291,9 @@ export class Child {
|
|
|
241
291
|
this.loggerDisposable.dispose();
|
|
242
292
|
}
|
|
243
293
|
|
|
244
|
-
createReverseHandle(fn: (...args: Array<any>) => mixed) {
|
|
294
|
+
createReverseHandle(fn: (...args: Array<any>) => mixed): Handle {
|
|
245
295
|
let handle = new Handle({
|
|
246
296
|
fn,
|
|
247
|
-
workerApi: this.workerApi,
|
|
248
297
|
childId: this.childId,
|
|
249
298
|
});
|
|
250
299
|
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(
|
|
53
|
-
|
|
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