@parcel/workers 2.0.0-nightly.140 → 2.0.0-nightly.1400

Sign up to get free protection for your applications and to get access to all the features.
package/lib/WorkerFarm.js CHANGED
@@ -10,177 +10,210 @@ Object.defineProperty(exports, "Handle", {
10
10
  }
11
11
  });
12
12
  exports.default = void 0;
13
-
14
- var _assert = _interopRequireDefault(require("assert"));
15
-
16
- var _nullthrows = _interopRequireDefault(require("nullthrows"));
17
-
18
- var _events = _interopRequireDefault(require("events"));
19
-
20
- var _core = require("@parcel/core");
21
-
22
- var _diagnostic = _interopRequireWildcard(require("@parcel/diagnostic"));
23
-
13
+ function _assert() {
14
+ const data = _interopRequireDefault(require("assert"));
15
+ _assert = function () {
16
+ return data;
17
+ };
18
+ return data;
19
+ }
20
+ function _nullthrows() {
21
+ const data = _interopRequireDefault(require("nullthrows"));
22
+ _nullthrows = function () {
23
+ return data;
24
+ };
25
+ return data;
26
+ }
27
+ function _events() {
28
+ const data = _interopRequireDefault(require("events"));
29
+ _events = function () {
30
+ return data;
31
+ };
32
+ return data;
33
+ }
34
+ function _core() {
35
+ const data = require("@parcel/core");
36
+ _core = function () {
37
+ return data;
38
+ };
39
+ return data;
40
+ }
41
+ function _diagnostic() {
42
+ const data = _interopRequireWildcard(require("@parcel/diagnostic"));
43
+ _diagnostic = function () {
44
+ return data;
45
+ };
46
+ return data;
47
+ }
24
48
  var _Worker = _interopRequireDefault(require("./Worker"));
25
-
26
49
  var _cpuCount = _interopRequireDefault(require("./cpuCount"));
27
-
28
50
  var _Handle = _interopRequireDefault(require("./Handle"));
29
-
30
51
  var _childState = require("./childState");
31
-
32
52
  var _backend = require("./backend");
33
-
34
- var _Profiler = _interopRequireDefault(require("./Profiler"));
35
-
36
- var _Trace = _interopRequireDefault(require("./Trace"));
37
-
38
- var _fs = _interopRequireDefault(require("fs"));
39
-
40
- var _logger = _interopRequireDefault(require("@parcel/logger"));
41
-
42
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
43
-
44
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
45
-
53
+ function _profiler() {
54
+ const data = require("@parcel/profiler");
55
+ _profiler = function () {
56
+ return data;
57
+ };
58
+ return data;
59
+ }
60
+ function _fs() {
61
+ const data = _interopRequireDefault(require("fs"));
62
+ _fs = function () {
63
+ return data;
64
+ };
65
+ return data;
66
+ }
67
+ function _logger() {
68
+ const data = _interopRequireDefault(require("@parcel/logger"));
69
+ _logger = function () {
70
+ return data;
71
+ };
72
+ return data;
73
+ }
74
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
75
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
46
76
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
47
-
48
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
49
-
50
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
51
-
52
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
53
-
54
- let profileId = 1;
55
77
  let referenceId = 1;
78
+ const DEFAULT_MAX_CONCURRENT_CALLS = 30;
56
79
 
57
80
  /**
58
81
  * workerPath should always be defined inside farmOptions
59
82
  */
60
- class WorkerFarm extends _events.default {
83
+
84
+ class WorkerFarm extends _events().default {
85
+ callQueue = [];
86
+ ending = false;
87
+ warmWorkers = 0;
88
+ workers = new Map();
89
+ handles = new Map();
90
+ sharedReferences = new Map();
91
+ sharedReferencesByValue = new Map();
92
+ serializedSharedReferences = new Map();
61
93
  constructor(farmOptions = {}) {
62
94
  super();
63
-
64
- _defineProperty(this, "callQueue", []);
65
-
66
- _defineProperty(this, "ending", false);
67
-
68
- _defineProperty(this, "localWorker", void 0);
69
-
70
- _defineProperty(this, "options", void 0);
71
-
72
- _defineProperty(this, "run", void 0);
73
-
74
- _defineProperty(this, "warmWorkers", 0);
75
-
76
- _defineProperty(this, "workers", new Map());
77
-
78
- _defineProperty(this, "handles", new Map());
79
-
80
- _defineProperty(this, "sharedReferences", new Map());
81
-
82
- _defineProperty(this, "sharedReferencesByValue", new Map());
83
-
84
- _defineProperty(this, "profiler", void 0);
85
-
86
- _defineProperty(this, "workerApi", {
87
- callMaster: async (request, awaitResponse = true) => {
88
- // $FlowFixMe
89
- let result = await this.processRequest(_objectSpread({}, request, {
90
- awaitResponse
91
- }));
92
- return (0, _core.deserialize)((0, _core.serialize)(result));
93
- },
94
- createReverseHandle: fn => this.createReverseHandle(fn),
95
- callChild: (childId, request) => new Promise((resolve, reject) => {
96
- (0, _nullthrows.default)(this.workers.get(childId)).call(_objectSpread({}, request, {
97
- resolve,
98
- reject,
99
- retries: 0
100
- }));
101
- }),
102
- getSharedReference: ref => this.sharedReferences.get(ref),
103
- resolveSharedReference: value => this.sharedReferencesByValue.get(value)
104
- });
105
-
106
- this.options = _objectSpread({
95
+ this.options = {
107
96
  maxConcurrentWorkers: WorkerFarm.getNumWorkers(),
108
- maxConcurrentCallsPerWorker: WorkerFarm.getConcurrentCallsPerWorker(),
97
+ maxConcurrentCallsPerWorker: WorkerFarm.getConcurrentCallsPerWorker(farmOptions.shouldTrace ? 1 : DEFAULT_MAX_CONCURRENT_CALLS),
109
98
  forcedKillTime: 500,
110
99
  warmWorkers: false,
111
100
  useLocalWorker: true,
112
101
  // TODO: setting this to false makes some tests fail, figure out why
113
- backend: (0, _backend.detectBackend)()
114
- }, farmOptions);
115
-
102
+ backend: (0, _backend.detectBackend)(),
103
+ ...farmOptions
104
+ };
116
105
  if (!this.options.workerPath) {
117
106
  throw new Error('Please provide a worker path!');
118
- } // $FlowFixMe this must be dynamic
119
-
107
+ }
120
108
 
109
+ // $FlowFixMe this must be dynamic
121
110
  this.localWorker = require(this.options.workerPath);
111
+ this.localWorkerInit = this.localWorker.childInit != null ? this.localWorker.childInit() : null;
122
112
  this.run = this.createHandle('run');
113
+
114
+ // Worker thread stdout is by default piped into the process stdout, if there are enough worker
115
+ // threads to exceed the default listener limit, then anything else piping into stdout will trigger
116
+ // the `MaxListenersExceededWarning`, so we should ensure the max listeners is at least equal to the
117
+ // number of workers + 1 for the main thread.
118
+ //
119
+ // Note this can't be fixed easily where other things pipe into stdout - even after starting > 10 worker
120
+ // threads `process.stdout.getMaxListeners()` will still return 10, however adding another pipe into `stdout`
121
+ // will give the warning with `<worker count + 1>` as the number of listeners.
122
+ process.stdout.setMaxListeners(Math.max(process.stdout.getMaxListeners(), WorkerFarm.getNumWorkers() + 1));
123
123
  this.startMaxWorkers();
124
124
  }
125
-
125
+ workerApi = {
126
+ callMaster: async (request, awaitResponse = true) => {
127
+ // $FlowFixMe
128
+ let result = await this.processRequest({
129
+ ...request,
130
+ awaitResponse
131
+ });
132
+ return (0, _core().deserialize)((0, _core().serialize)(result));
133
+ },
134
+ createReverseHandle: fn => this.createReverseHandle(fn),
135
+ callChild: (childId, request) => new Promise((resolve, reject) => {
136
+ (0, _nullthrows().default)(this.workers.get(childId)).call({
137
+ ...request,
138
+ resolve,
139
+ reject,
140
+ retries: 0
141
+ });
142
+ }),
143
+ runHandle: (handle, args) => this.workerApi.callChild((0, _nullthrows().default)(handle.childId), {
144
+ handle: handle.id,
145
+ args
146
+ }),
147
+ getSharedReference: ref => this.sharedReferences.get(ref),
148
+ resolveSharedReference: value => this.sharedReferencesByValue.get(value)
149
+ };
126
150
  warmupWorker(method, args) {
127
151
  // Workers are already stopping
128
152
  if (this.ending) {
129
153
  return;
130
- } // Workers are not warmed up yet.
154
+ }
155
+
156
+ // Workers are not warmed up yet.
131
157
  // Send the job to a remote worker in the background,
132
158
  // but use the result from the local worker - it will be faster.
133
-
134
-
135
159
  let promise = this.addCall(method, [...args, true]);
136
-
137
160
  if (promise) {
138
161
  promise.then(() => {
139
162
  this.warmWorkers++;
140
-
141
163
  if (this.warmWorkers >= this.workers.size) {
142
164
  this.emit('warmedup');
143
165
  }
144
166
  }).catch(() => {});
145
167
  }
146
168
  }
147
-
148
169
  shouldStartRemoteWorkers() {
149
170
  return this.options.maxConcurrentWorkers > 0 || !this.options.useLocalWorker;
150
171
  }
151
-
152
- createHandle(method) {
153
- return (...args) => {
172
+ createHandle(method, useMainThread = false) {
173
+ if (!this.options.useLocalWorker) {
174
+ useMainThread = false;
175
+ }
176
+ return async (...args) => {
154
177
  // Child process workers are slow to start (~600ms).
155
178
  // While we're waiting, just run on the main thread.
156
179
  // This significantly speeds up startup time.
157
- if (this.shouldUseRemoteWorkers()) {
180
+ if (this.shouldUseRemoteWorkers() && !useMainThread) {
158
181
  return this.addCall(method, [...args, false]);
159
182
  } else {
160
183
  if (this.options.warmWorkers && this.shouldStartRemoteWorkers()) {
161
184
  this.warmupWorker(method, args);
162
185
  }
163
-
164
- let processedArgs = (0, _core.restoreDeserializedObject)((0, _core.prepareForSerialization)([...args, false]));
186
+ let processedArgs;
187
+ if (!useMainThread) {
188
+ processedArgs = (0, _core().restoreDeserializedObject)((0, _core().prepareForSerialization)([...args, false]));
189
+ } else {
190
+ processedArgs = args;
191
+ }
192
+ if (this.localWorkerInit != null) {
193
+ await this.localWorkerInit;
194
+ this.localWorkerInit = null;
195
+ }
165
196
  return this.localWorker[method](this.workerApi, ...processedArgs);
166
197
  }
167
198
  };
168
199
  }
169
-
170
200
  onError(error, worker) {
171
201
  // Handle ipc errors
172
202
  if (error.code === 'ERR_IPC_CHANNEL_CLOSED') {
173
203
  return this.stopWorker(worker);
204
+ } else {
205
+ _logger().default.error(error, '@parcel/workers');
174
206
  }
175
207
  }
176
-
177
208
  startChild() {
178
209
  let worker = new _Worker.default({
179
210
  forcedKillTime: this.options.forcedKillTime,
180
211
  backend: this.options.backend,
181
- patchConsole: this.options.patchConsole
212
+ shouldPatchConsole: this.options.shouldPatchConsole,
213
+ shouldTrace: this.options.shouldTrace,
214
+ sharedReferences: this.sharedReferences
182
215
  });
183
- worker.fork((0, _nullthrows.default)(this.options.workerPath));
216
+ worker.fork((0, _nullthrows().default)(this.options.workerPath));
184
217
  worker.on('request', data => this.processRequest(data, worker));
185
218
  worker.on('ready', () => this.processQueue());
186
219
  worker.on('response', () => this.processQueue());
@@ -188,48 +221,49 @@ class WorkerFarm extends _events.default {
188
221
  worker.once('exit', () => this.stopWorker(worker));
189
222
  this.workers.set(worker.id, worker);
190
223
  }
191
-
192
224
  async stopWorker(worker) {
193
225
  if (!worker.stopped) {
194
226
  this.workers.delete(worker.id);
195
227
  worker.isStopping = true;
196
-
197
228
  if (worker.calls.size) {
198
229
  for (let call of worker.calls.values()) {
199
230
  call.retries++;
200
231
  this.callQueue.unshift(call);
201
232
  }
202
233
  }
203
-
204
234
  worker.calls.clear();
205
- await worker.stop(); // Process any requests that failed and start a new worker
235
+ await worker.stop();
206
236
 
237
+ // Process any requests that failed and start a new worker
207
238
  this.processQueue();
208
239
  }
209
240
  }
210
-
211
241
  processQueue() {
212
242
  if (this.ending || !this.callQueue.length) return;
213
-
214
243
  if (this.workers.size < this.options.maxConcurrentWorkers) {
215
244
  this.startChild();
216
245
  }
217
-
218
- for (let worker of this.workers.values()) {
246
+ let workers = [...this.workers.values()].sort((a, b) => a.calls.size - b.calls.size);
247
+ for (let worker of workers) {
219
248
  if (!this.callQueue.length) {
220
249
  break;
221
250
  }
222
-
223
251
  if (!worker.ready || worker.stopped || worker.isStopping) {
224
252
  continue;
225
253
  }
226
-
227
254
  if (worker.calls.size < this.options.maxConcurrentCallsPerWorker) {
228
- worker.call(this.callQueue.shift());
255
+ this.callWorker(worker, this.callQueue.shift());
229
256
  }
230
257
  }
231
258
  }
232
-
259
+ async callWorker(worker, call) {
260
+ for (let ref of this.sharedReferences.keys()) {
261
+ if (!worker.sentSharedReferences.has(ref)) {
262
+ await worker.sendSharedReference(ref, this.getSerializedSharedReference(ref));
263
+ }
264
+ }
265
+ worker.call(call);
266
+ }
233
267
  async processRequest(data, worker) {
234
268
  let {
235
269
  method,
@@ -240,73 +274,63 @@ class WorkerFarm extends _events.default {
240
274
  handle: handleId
241
275
  } = data;
242
276
  let mod;
243
-
244
277
  if (handleId != null) {
245
- mod = (0, _nullthrows.default)(this.handles.get(handleId)).fn;
278
+ var _this$handles$get;
279
+ mod = (0, _nullthrows().default)((_this$handles$get = this.handles.get(handleId)) === null || _this$handles$get === void 0 ? void 0 : _this$handles$get.fn);
246
280
  } else if (location) {
247
281
  // $FlowFixMe this must be dynamic
248
282
  mod = require(location);
249
283
  } else {
250
284
  throw new Error('Unknown request');
251
285
  }
252
-
253
286
  const responseFromContent = content => ({
254
287
  idx,
255
288
  type: 'response',
256
289
  contentType: 'data',
257
290
  content
258
291
  });
259
-
260
292
  const errorResponseFromError = e => ({
261
293
  idx,
262
294
  type: 'response',
263
295
  contentType: 'error',
264
- content: (0, _diagnostic.anyToDiagnostic)(e)
296
+ content: (0, _diagnostic().anyToDiagnostic)(e)
265
297
  });
266
-
267
298
  let result;
268
-
269
299
  if (method == null) {
270
300
  try {
271
- result = responseFromContent((await mod(...args)));
301
+ result = responseFromContent(await mod(...args));
272
302
  } catch (e) {
273
303
  result = errorResponseFromError(e);
274
304
  }
275
305
  } else {
276
306
  // ESModule default interop
277
- // $FlowFixMe
278
307
  if (mod.__esModule && !mod[method] && mod.default) {
279
308
  mod = mod.default;
280
309
  }
281
-
282
310
  try {
283
311
  // $FlowFixMe
284
- result = responseFromContent((await mod[method](...args)));
312
+ result = responseFromContent(await mod[method](...args));
285
313
  } catch (e) {
286
314
  result = errorResponseFromError(e);
287
315
  }
288
316
  }
289
-
290
317
  if (awaitResponse) {
291
318
  if (worker) {
292
319
  worker.send(result);
293
320
  } else {
294
321
  if (result.contentType === 'error') {
295
- throw new _diagnostic.default({
322
+ throw new (_diagnostic().default)({
296
323
  diagnostic: result.content
297
324
  });
298
325
  }
299
-
300
326
  return result.content;
301
327
  }
302
328
  }
303
329
  }
304
-
305
330
  addCall(method, args) {
306
331
  if (this.ending) {
307
332
  throw new Error('Cannot add a worker call if workerfarm is ending.');
308
333
  }
309
-
310
334
  return new Promise((resolve, reject) => {
311
335
  this.callQueue.push({
312
336
  method,
@@ -318,91 +342,87 @@ class WorkerFarm extends _events.default {
318
342
  this.processQueue();
319
343
  });
320
344
  }
321
-
322
345
  async end() {
323
346
  this.ending = true;
324
-
347
+ await Promise.all(Array.from(this.workers.values()).map(worker => this.stopWorker(worker)));
325
348
  for (let handle of this.handles.values()) {
326
349
  handle.dispose();
327
350
  }
328
-
329
351
  this.handles = new Map();
330
352
  this.sharedReferences = new Map();
331
353
  this.sharedReferencesByValue = new Map();
332
- await Promise.all(Array.from(this.workers.values()).map(worker => this.stopWorker(worker)));
333
354
  this.ending = false;
334
355
  }
335
-
336
356
  startMaxWorkers() {
337
357
  // Starts workers until the maximum is reached
338
358
  if (this.workers.size < this.options.maxConcurrentWorkers) {
339
359
  let toStart = this.options.maxConcurrentWorkers - this.workers.size;
340
-
341
360
  while (toStart--) {
342
361
  this.startChild();
343
362
  }
344
363
  }
345
364
  }
346
-
347
365
  shouldUseRemoteWorkers() {
348
366
  return !this.options.useLocalWorker || (this.warmWorkers >= this.workers.size || !this.options.warmWorkers) && this.options.maxConcurrentWorkers > 0;
349
367
  }
350
-
351
368
  createReverseHandle(fn) {
352
369
  let handle = new _Handle.default({
353
- fn,
354
- workerApi: this.workerApi
370
+ fn
355
371
  });
356
372
  this.handles.set(handle.id, handle);
357
373
  return handle;
358
374
  }
359
-
360
- async createSharedReference(value) {
375
+ createSharedReference(value, isCacheable = true) {
361
376
  let ref = referenceId++;
362
377
  this.sharedReferences.set(ref, value);
363
378
  this.sharedReferencesByValue.set(value, ref);
364
- let promises = [];
365
-
366
- for (let worker of this.workers.values()) {
367
- promises.push(new Promise((resolve, reject) => {
368
- worker.call({
369
- method: 'createSharedReference',
370
- args: [ref, value],
371
- resolve,
372
- reject,
373
- retries: 0
374
- });
375
- }));
379
+ if (!isCacheable) {
380
+ this.serializedSharedReferences.set(ref, null);
376
381
  }
377
-
378
- await Promise.all(promises);
379
382
  return {
380
383
  ref,
381
384
  dispose: () => {
382
385
  this.sharedReferences.delete(ref);
383
386
  this.sharedReferencesByValue.delete(value);
387
+ this.serializedSharedReferences.delete(ref);
384
388
  let promises = [];
385
-
386
389
  for (let worker of this.workers.values()) {
390
+ if (!worker.sentSharedReferences.has(ref)) {
391
+ continue;
392
+ }
393
+ worker.sentSharedReferences.delete(ref);
387
394
  promises.push(new Promise((resolve, reject) => {
388
395
  worker.call({
389
396
  method: 'deleteSharedReference',
390
397
  args: [ref],
391
398
  resolve,
392
399
  reject,
400
+ skipReadyCheck: true,
393
401
  retries: 0
394
402
  });
395
403
  }));
396
404
  }
397
-
398
405
  return Promise.all(promises);
399
406
  }
400
407
  };
401
408
  }
409
+ getSerializedSharedReference(ref) {
410
+ let cached = this.serializedSharedReferences.get(ref);
411
+ if (cached) {
412
+ return cached;
413
+ }
414
+ let value = this.sharedReferences.get(ref);
415
+ let buf = (0, _core().serialize)(value).buffer;
402
416
 
417
+ // If the reference was created with the isCacheable option set to false,
418
+ // serializedSharedReferences will contain `null` as the value.
419
+ if (cached !== null) {
420
+ this.serializedSharedReferences.set(ref, buf);
421
+ }
422
+ return buf;
423
+ }
403
424
  async startProfile() {
404
425
  let promises = [];
405
-
406
426
  for (let worker of this.workers.values()) {
407
427
  promises.push(new Promise((resolve, reject) => {
408
428
  worker.call({
@@ -410,24 +430,21 @@ class WorkerFarm extends _events.default {
410
430
  args: [],
411
431
  resolve,
412
432
  reject,
413
- retries: 0
433
+ retries: 0,
434
+ skipReadyCheck: true
414
435
  });
415
436
  }));
416
437
  }
417
-
418
- this.profiler = new _Profiler.default();
438
+ this.profiler = new (_profiler().SamplingProfiler)();
419
439
  promises.push(this.profiler.startProfiling());
420
440
  await Promise.all(promises);
421
441
  }
422
-
423
442
  async endProfile() {
424
443
  if (!this.profiler) {
425
444
  return;
426
445
  }
427
-
428
446
  let promises = [this.profiler.stopProfiling()];
429
447
  let names = ['Master'];
430
-
431
448
  for (let worker of this.workers.values()) {
432
449
  names.push('Worker ' + worker.id);
433
450
  promises.push(new Promise((resolve, reject) => {
@@ -436,48 +453,83 @@ class WorkerFarm extends _events.default {
436
453
  args: [],
437
454
  resolve,
438
455
  reject,
439
- retries: 0
456
+ retries: 0,
457
+ skipReadyCheck: true
440
458
  });
441
459
  }));
442
460
  }
443
-
444
461
  var profiles = await Promise.all(promises);
445
- let trace = new _Trace.default();
446
- let filename = `profile-${profileId++}.trace`;
447
- let stream = trace.pipe(_fs.default.createWriteStream(filename));
448
-
462
+ let trace = new (_profiler().Trace)();
463
+ let filename = `profile-${getTimeId()}.trace`;
464
+ let stream = trace.pipe(_fs().default.createWriteStream(filename));
449
465
  for (let profile of profiles) {
450
466
  trace.addCPUProfile(names.shift(), profile);
451
467
  }
452
-
453
468
  trace.flush();
454
469
  await new Promise(resolve => {
455
470
  stream.once('finish', resolve);
456
471
  });
457
-
458
- _logger.default.info({
472
+ _logger().default.info({
459
473
  origin: '@parcel/workers',
460
- message: `Wrote profile to ${filename}`
474
+ message: (0, _diagnostic().md)`Wrote profile to ${filename}`
461
475
  });
462
476
  }
463
-
477
+ async callAllWorkers(method, args) {
478
+ let promises = [];
479
+ for (let worker of this.workers.values()) {
480
+ promises.push(new Promise((resolve, reject) => {
481
+ worker.call({
482
+ method,
483
+ args,
484
+ resolve,
485
+ reject,
486
+ retries: 0
487
+ });
488
+ }));
489
+ }
490
+ promises.push(this.localWorker[method](this.workerApi, ...args));
491
+ await Promise.all(promises);
492
+ }
493
+ async takeHeapSnapshot() {
494
+ let snapshotId = getTimeId();
495
+ try {
496
+ let snapshotPaths = await Promise.all([...this.workers.values()].map(worker => new Promise((resolve, reject) => {
497
+ worker.call({
498
+ method: 'takeHeapSnapshot',
499
+ args: [snapshotId],
500
+ resolve,
501
+ reject,
502
+ retries: 0,
503
+ skipReadyCheck: true
504
+ });
505
+ })));
506
+ _logger().default.info({
507
+ origin: '@parcel/workers',
508
+ message: (0, _diagnostic().md)`Wrote heap snapshots to the following paths:\n${snapshotPaths.join('\n')}`
509
+ });
510
+ } catch {
511
+ _logger().default.error({
512
+ origin: '@parcel/workers',
513
+ message: 'Unable to take heap snapshots. Note: requires Node 11.13.0+'
514
+ });
515
+ }
516
+ }
464
517
  static getNumWorkers() {
465
- return process.env.PARCEL_WORKERS ? parseInt(process.env.PARCEL_WORKERS, 10) : (0, _cpuCount.default)();
518
+ return process.env.PARCEL_WORKERS ? parseInt(process.env.PARCEL_WORKERS, 10) : Math.min(4, Math.ceil((0, _cpuCount.default)() / 2));
466
519
  }
467
-
468
520
  static isWorker() {
469
521
  return !!_childState.child;
470
522
  }
471
-
472
523
  static getWorkerApi() {
473
- (0, _assert.default)(_childState.child != null, 'WorkerFarm.getWorkerApi can only be called within workers');
524
+ (0, _assert().default)(_childState.child != null, 'WorkerFarm.getWorkerApi can only be called within workers');
474
525
  return _childState.child.workerApi;
475
526
  }
476
-
477
- static getConcurrentCallsPerWorker() {
478
- return parseInt(process.env.PARCEL_MAX_CONCURRENT_CALLS, 10) || 5;
527
+ static getConcurrentCallsPerWorker(defaultValue = DEFAULT_MAX_CONCURRENT_CALLS) {
528
+ return parseInt(process.env.PARCEL_MAX_CONCURRENT_CALLS, 10) || defaultValue;
479
529
  }
480
-
481
530
  }
482
-
483
- exports.default = WorkerFarm;
531
+ exports.default = WorkerFarm;
532
+ function getTimeId() {
533
+ let now = new Date();
534
+ return String(now.getFullYear()) + String(now.getMonth() + 1).padStart(2, '0') + String(now.getDate()).padStart(2, '0') + '-' + String(now.getHours()).padStart(2, '0') + String(now.getMinutes()).padStart(2, '0') + String(now.getSeconds()).padStart(2, '0');
535
+ }