@atlaspack/workers 2.14.31 → 2.14.32
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/CHANGELOG.md +10 -0
- package/dist/Handle.js +33 -0
- package/dist/Worker.js +180 -0
- package/dist/WorkerFarm.js +541 -0
- package/dist/backend.js +34 -0
- package/dist/bus.js +24 -0
- package/dist/child.js +290 -0
- package/dist/childState.js +11 -0
- package/dist/cpuCount.js +72 -0
- package/dist/index.js +44 -0
- package/dist/process/ProcessChild.js +48 -0
- package/dist/process/ProcessWorker.js +68 -0
- package/dist/threads/ThreadsChild.js +31 -0
- package/dist/threads/ThreadsWorker.js +47 -0
- package/dist/types.js +2 -0
- package/dist/web/WebChild.js +34 -0
- package/dist/web/WebWorker.js +70 -0
- package/package.json +5 -6
- package/tsconfig.json +25 -2
- package/tsconfig.tsbuildinfo +1 -0
package/dist/child.js
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.Child = void 0;
|
|
40
|
+
const assert_1 = __importDefault(require("assert"));
|
|
41
|
+
const nullthrows_1 = __importDefault(require("nullthrows"));
|
|
42
|
+
const build_cache_1 = require("@atlaspack/build-cache");
|
|
43
|
+
const logger_1 = __importStar(require("@atlaspack/logger"));
|
|
44
|
+
const diagnostic_1 = __importStar(require("@atlaspack/diagnostic"));
|
|
45
|
+
const bus_1 = __importDefault(require("./bus"));
|
|
46
|
+
const profiler_1 = require("@atlaspack/profiler");
|
|
47
|
+
const Handle_1 = __importDefault(require("./Handle"));
|
|
48
|
+
// /flow-to-ts helpers
|
|
49
|
+
// The import of './Handle' should really be imported eagerly (with @babel/plugin-transform-modules-commonjs's lazy mode).
|
|
50
|
+
const Handle = Handle_1.default;
|
|
51
|
+
class Child {
|
|
52
|
+
constructor(ChildBackend) {
|
|
53
|
+
this.callQueue = [];
|
|
54
|
+
this.maxConcurrentCalls = 10;
|
|
55
|
+
this.responseId = 0;
|
|
56
|
+
this.responseQueue = new Map();
|
|
57
|
+
// @ts-expect-error TS2749
|
|
58
|
+
this.handles = new Map();
|
|
59
|
+
this.sharedReferences = new Map();
|
|
60
|
+
this.sharedReferencesByValue = new Map();
|
|
61
|
+
this.workerApi = {
|
|
62
|
+
callMaster: (request, awaitResponse = true) => this.addCall(request, awaitResponse),
|
|
63
|
+
// @ts-expect-error TS2749
|
|
64
|
+
createReverseHandle: (fn) => this.createReverseHandle(fn),
|
|
65
|
+
// @ts-expect-error TS2749
|
|
66
|
+
runHandle: (handle, args) => this.workerApi.callMaster({ handle: handle.id, args }, true),
|
|
67
|
+
getSharedReference: (ref) => this.sharedReferences.get(ref),
|
|
68
|
+
resolveSharedReference: (value) => this.sharedReferencesByValue.get(value),
|
|
69
|
+
};
|
|
70
|
+
this.child = new ChildBackend((m) => {
|
|
71
|
+
this.messageListener(m);
|
|
72
|
+
}, () => this.handleEnd());
|
|
73
|
+
// Monitior all logging events inside this child process and forward to
|
|
74
|
+
// the main process via the bus.
|
|
75
|
+
this.loggerDisposable = logger_1.default.onLog((event) => {
|
|
76
|
+
bus_1.default.emit('logEvent', event);
|
|
77
|
+
});
|
|
78
|
+
// .. and do the same for trace events
|
|
79
|
+
this.tracerDisposable = profiler_1.tracer.onTrace((event) => {
|
|
80
|
+
bus_1.default.emit('traceEvent', event);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
messageListener(message) {
|
|
84
|
+
if (message.type === 'response') {
|
|
85
|
+
return this.handleResponse(message);
|
|
86
|
+
}
|
|
87
|
+
else if (message.type === 'request') {
|
|
88
|
+
return this.handleRequest(message);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
send(data) {
|
|
92
|
+
this.child.send(data);
|
|
93
|
+
}
|
|
94
|
+
async childInit(module, childId) {
|
|
95
|
+
this.module = require(module);
|
|
96
|
+
this.childId = childId;
|
|
97
|
+
if (this.module.childInit != null) {
|
|
98
|
+
await this.module.childInit();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async handleRequest(data) {
|
|
102
|
+
let { idx, method, args, handle: handleId } = data;
|
|
103
|
+
let child = (0, nullthrows_1.default)(data.child);
|
|
104
|
+
const responseFromContent = (content) => ({
|
|
105
|
+
idx,
|
|
106
|
+
child,
|
|
107
|
+
type: 'response',
|
|
108
|
+
contentType: 'data',
|
|
109
|
+
content,
|
|
110
|
+
});
|
|
111
|
+
const errorResponseFromError = (e) => ({
|
|
112
|
+
idx,
|
|
113
|
+
child,
|
|
114
|
+
type: 'response',
|
|
115
|
+
contentType: 'error',
|
|
116
|
+
content: (0, diagnostic_1.anyToDiagnostic)(e),
|
|
117
|
+
});
|
|
118
|
+
let result;
|
|
119
|
+
if (handleId != null) {
|
|
120
|
+
try {
|
|
121
|
+
let fn = (0, nullthrows_1.default)(this.handles.get(handleId)?.fn);
|
|
122
|
+
result = responseFromContent(fn(...args));
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
result = errorResponseFromError(e);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else if (method === 'childInit') {
|
|
129
|
+
try {
|
|
130
|
+
let [moduleName, childOptions] = args;
|
|
131
|
+
if (childOptions.shouldPatchConsole) {
|
|
132
|
+
(0, logger_1.patchConsole)();
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
(0, logger_1.unpatchConsole)();
|
|
136
|
+
}
|
|
137
|
+
if (childOptions.shouldTrace) {
|
|
138
|
+
profiler_1.tracer.enable();
|
|
139
|
+
}
|
|
140
|
+
result = responseFromContent(await this.childInit(moduleName, child));
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
result = errorResponseFromError(e);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else if (method === 'startProfile') {
|
|
147
|
+
this.profiler = new profiler_1.SamplingProfiler();
|
|
148
|
+
try {
|
|
149
|
+
result = responseFromContent(await this.profiler.startProfiling());
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
result = errorResponseFromError(e);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else if (method === 'endProfile') {
|
|
156
|
+
try {
|
|
157
|
+
let res = this.profiler ? await this.profiler.stopProfiling() : null;
|
|
158
|
+
result = responseFromContent(res);
|
|
159
|
+
}
|
|
160
|
+
catch (e) {
|
|
161
|
+
result = errorResponseFromError(e);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else if (method === 'takeHeapSnapshot') {
|
|
165
|
+
try {
|
|
166
|
+
let v8 = require('v8');
|
|
167
|
+
result = responseFromContent(v8.writeHeapSnapshot('heap-' +
|
|
168
|
+
args[0] +
|
|
169
|
+
'-' +
|
|
170
|
+
(this.childId ? 'worker' + this.childId : 'main') +
|
|
171
|
+
'.heapsnapshot'));
|
|
172
|
+
}
|
|
173
|
+
catch (e) {
|
|
174
|
+
result = errorResponseFromError(e);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else if (method === 'createSharedReference') {
|
|
178
|
+
let [ref, _value] = args;
|
|
179
|
+
let value = _value instanceof ArrayBuffer
|
|
180
|
+
? // In the case the value is pre-serialized as a buffer,
|
|
181
|
+
// deserialize it.
|
|
182
|
+
(0, build_cache_1.deserialize)(Buffer.from(_value))
|
|
183
|
+
: _value;
|
|
184
|
+
this.sharedReferences.set(ref, value);
|
|
185
|
+
this.sharedReferencesByValue.set(value, ref);
|
|
186
|
+
result = responseFromContent(null);
|
|
187
|
+
}
|
|
188
|
+
else if (method === 'deleteSharedReference') {
|
|
189
|
+
let ref = args[0];
|
|
190
|
+
let value = this.sharedReferences.get(ref);
|
|
191
|
+
this.sharedReferencesByValue.delete(value);
|
|
192
|
+
this.sharedReferences.delete(ref);
|
|
193
|
+
result = responseFromContent(null);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
try {
|
|
197
|
+
result = responseFromContent(
|
|
198
|
+
// @ts-expect-error TS2538
|
|
199
|
+
await this.module[method](this.workerApi, ...args));
|
|
200
|
+
}
|
|
201
|
+
catch (e) {
|
|
202
|
+
result = errorResponseFromError(e);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
this.send(result);
|
|
207
|
+
}
|
|
208
|
+
catch (e) {
|
|
209
|
+
result = this.send(errorResponseFromError(e));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
handleResponse(data) {
|
|
213
|
+
let idx = (0, nullthrows_1.default)(data.idx);
|
|
214
|
+
let contentType = data.contentType;
|
|
215
|
+
let content = data.content;
|
|
216
|
+
let call = (0, nullthrows_1.default)(this.responseQueue.get(idx));
|
|
217
|
+
if (contentType === 'error') {
|
|
218
|
+
(0, assert_1.default)(typeof content !== 'string');
|
|
219
|
+
call.reject(new diagnostic_1.default({ diagnostic: content }));
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
call.resolve(content);
|
|
223
|
+
}
|
|
224
|
+
this.responseQueue.delete(idx);
|
|
225
|
+
// Process the next call
|
|
226
|
+
this.processQueue();
|
|
227
|
+
}
|
|
228
|
+
// Keep in mind to make sure responses to these calls are JSON.Stringify safe
|
|
229
|
+
addCall(request, awaitResponse = true) {
|
|
230
|
+
let call = {
|
|
231
|
+
...request,
|
|
232
|
+
type: 'request',
|
|
233
|
+
child: this.childId,
|
|
234
|
+
// @ts-expect-error TS2322
|
|
235
|
+
awaitResponse,
|
|
236
|
+
resolve: () => { },
|
|
237
|
+
reject: () => { },
|
|
238
|
+
};
|
|
239
|
+
let promise;
|
|
240
|
+
if (awaitResponse) {
|
|
241
|
+
promise = new Promise((resolve, reject) => {
|
|
242
|
+
call.resolve = resolve;
|
|
243
|
+
call.reject = reject;
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
this.callQueue.push(call);
|
|
247
|
+
this.processQueue();
|
|
248
|
+
return promise ?? Promise.resolve();
|
|
249
|
+
}
|
|
250
|
+
sendRequest(call) {
|
|
251
|
+
let idx;
|
|
252
|
+
if (call.awaitResponse) {
|
|
253
|
+
idx = this.responseId++;
|
|
254
|
+
this.responseQueue.set(idx, call);
|
|
255
|
+
}
|
|
256
|
+
this.send({
|
|
257
|
+
idx,
|
|
258
|
+
child: call.child,
|
|
259
|
+
type: call.type,
|
|
260
|
+
location: call.location,
|
|
261
|
+
handle: call.handle,
|
|
262
|
+
method: call.method,
|
|
263
|
+
args: call.args,
|
|
264
|
+
awaitResponse: call.awaitResponse,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
processQueue() {
|
|
268
|
+
if (!this.callQueue.length) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (this.responseQueue.size < this.maxConcurrentCalls) {
|
|
272
|
+
// @ts-expect-error TS2345
|
|
273
|
+
this.sendRequest(this.callQueue.shift());
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
handleEnd() {
|
|
277
|
+
this.loggerDisposable.dispose();
|
|
278
|
+
this.tracerDisposable.dispose();
|
|
279
|
+
}
|
|
280
|
+
// @ts-expect-error TS2749
|
|
281
|
+
createReverseHandle(fn) {
|
|
282
|
+
let handle = new Handle({
|
|
283
|
+
fn,
|
|
284
|
+
childId: this.childId,
|
|
285
|
+
});
|
|
286
|
+
this.handles.set(handle.id, handle);
|
|
287
|
+
return handle;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
exports.Child = Child;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.child = void 0;
|
|
4
|
+
exports.setChild = setChild;
|
|
5
|
+
// This file is imported by both the WorkerFarm and child implementation.
|
|
6
|
+
// When a worker is inited, it sets the state in this file.
|
|
7
|
+
// This way, WorkerFarm can access the state without directly importing the child code.
|
|
8
|
+
exports.child = null;
|
|
9
|
+
function setChild(c) {
|
|
10
|
+
exports.child = c;
|
|
11
|
+
}
|
package/dist/cpuCount.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.detectRealCores = detectRealCores;
|
|
7
|
+
exports.default = getCores;
|
|
8
|
+
const os_1 = __importDefault(require("os"));
|
|
9
|
+
const child_process_1 = require("child_process");
|
|
10
|
+
const exec = (command) => {
|
|
11
|
+
try {
|
|
12
|
+
let stdout = (0, child_process_1.execSync)(command, {
|
|
13
|
+
encoding: 'utf8',
|
|
14
|
+
// This prevents the command from outputting to the console
|
|
15
|
+
stdio: [null, null, null],
|
|
16
|
+
});
|
|
17
|
+
return stdout.trim();
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
function detectRealCores() {
|
|
24
|
+
let platform = os_1.default.platform();
|
|
25
|
+
let amount = 0;
|
|
26
|
+
if (platform === 'linux') {
|
|
27
|
+
amount = parseInt(exec('lscpu -p | egrep -v "^#" | sort -u -t, -k 2,4 | wc -l'), 10);
|
|
28
|
+
}
|
|
29
|
+
else if (platform === 'darwin') {
|
|
30
|
+
amount = parseInt(exec('sysctl -n hw.physicalcpu_max'), 10);
|
|
31
|
+
}
|
|
32
|
+
else if (platform === 'win32') {
|
|
33
|
+
const str = exec('wmic cpu get NumberOfCores').match(/\d+/g);
|
|
34
|
+
if (str !== null) {
|
|
35
|
+
amount = parseInt(str.filter((n) => n !== '')[0], 10);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!amount || amount <= 0) {
|
|
39
|
+
throw new Error('Could not detect cpu count!');
|
|
40
|
+
}
|
|
41
|
+
return amount;
|
|
42
|
+
}
|
|
43
|
+
// @ts-expect-error TS7034
|
|
44
|
+
let cores;
|
|
45
|
+
function getCores(bypassCache = false) {
|
|
46
|
+
// Do not re-run commands if we already have the count...
|
|
47
|
+
// @ts-expect-error TS7005
|
|
48
|
+
if (cores && !bypassCache) {
|
|
49
|
+
return cores;
|
|
50
|
+
}
|
|
51
|
+
// @ts-expect-error TS2339
|
|
52
|
+
if (process.browser) {
|
|
53
|
+
cores = navigator.hardwareConcurrency / 2;
|
|
54
|
+
}
|
|
55
|
+
// @ts-expect-error TS7005
|
|
56
|
+
if (!cores) {
|
|
57
|
+
try {
|
|
58
|
+
cores = detectRealCores();
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
// Guess the amount of real cores
|
|
62
|
+
cores = os_1.default
|
|
63
|
+
.cpus()
|
|
64
|
+
.filter((cpu, index) => !cpu.model.includes('Intel') || index % 2 === 1).length;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Another fallback
|
|
68
|
+
if (!cores) {
|
|
69
|
+
cores = 1;
|
|
70
|
+
}
|
|
71
|
+
return cores;
|
|
72
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Handle = exports.bus = void 0;
|
|
7
|
+
const assert_1 = __importDefault(require("assert"));
|
|
8
|
+
const WorkerFarm_1 = __importDefault(require("./WorkerFarm"));
|
|
9
|
+
const logger_1 = __importDefault(require("@atlaspack/logger"));
|
|
10
|
+
const bus_1 = __importDefault(require("./bus"));
|
|
11
|
+
exports.bus = bus_1.default;
|
|
12
|
+
const profiler_1 = require("@atlaspack/profiler");
|
|
13
|
+
if (!WorkerFarm_1.default.isWorker()) {
|
|
14
|
+
// Forward all logger events originating from workers into the main process
|
|
15
|
+
bus_1.default.on('logEvent', (e) => {
|
|
16
|
+
switch (e.level) {
|
|
17
|
+
case 'info':
|
|
18
|
+
logger_1.default.info(e.diagnostics);
|
|
19
|
+
break;
|
|
20
|
+
case 'progress':
|
|
21
|
+
(0, assert_1.default)(typeof e.message === 'string');
|
|
22
|
+
logger_1.default.progress(e.message);
|
|
23
|
+
break;
|
|
24
|
+
case 'verbose':
|
|
25
|
+
logger_1.default.verbose(e.diagnostics);
|
|
26
|
+
break;
|
|
27
|
+
case 'warn':
|
|
28
|
+
logger_1.default.warn(e.diagnostics);
|
|
29
|
+
break;
|
|
30
|
+
case 'error':
|
|
31
|
+
logger_1.default.error(e.diagnostics);
|
|
32
|
+
break;
|
|
33
|
+
default:
|
|
34
|
+
throw new Error('Unknown log level');
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
// Forward all trace events originating from workers into the main process
|
|
38
|
+
bus_1.default.on('traceEvent', (e) => {
|
|
39
|
+
profiler_1.tracer.trace(e);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
exports.default = WorkerFarm_1.default;
|
|
43
|
+
var WorkerFarm_2 = require("./WorkerFarm");
|
|
44
|
+
Object.defineProperty(exports, "Handle", { enumerable: true, get: function () { return WorkerFarm_2.Handle; } });
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const build_cache_1 = require("@atlaspack/build-cache");
|
|
7
|
+
const nullthrows_1 = __importDefault(require("nullthrows"));
|
|
8
|
+
const child_1 = require("../child");
|
|
9
|
+
const childState_1 = require("../childState");
|
|
10
|
+
// @ts-expect-error TS2420
|
|
11
|
+
class ProcessChild {
|
|
12
|
+
constructor(onMessage, onExit) {
|
|
13
|
+
if (!process.send) {
|
|
14
|
+
throw new Error('Only create ProcessChild instances in a worker!');
|
|
15
|
+
}
|
|
16
|
+
this.onMessage = onMessage;
|
|
17
|
+
this.onExit = onExit;
|
|
18
|
+
// @ts-expect-error TS2345
|
|
19
|
+
process.on('message', (data) => this.handleMessage(data));
|
|
20
|
+
}
|
|
21
|
+
handleMessage(data) {
|
|
22
|
+
if (data === 'die') {
|
|
23
|
+
return this.stop();
|
|
24
|
+
}
|
|
25
|
+
this.onMessage((0, build_cache_1.deserialize)(Buffer.from(data, 'base64')));
|
|
26
|
+
}
|
|
27
|
+
send(data) {
|
|
28
|
+
let processSend = (0, nullthrows_1.default)(process.send).bind(process);
|
|
29
|
+
// @ts-expect-error TS7006
|
|
30
|
+
processSend((0, build_cache_1.serialize)(data).toString('base64'), (err) => {
|
|
31
|
+
if (err && err instanceof Error) {
|
|
32
|
+
// @ts-expect-error TS2339
|
|
33
|
+
if (err.code === 'ERR_IPC_CHANNEL_CLOSED') {
|
|
34
|
+
// IPC connection closed
|
|
35
|
+
// no need to keep the worker running if it can't send or receive data
|
|
36
|
+
return this.stop();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
stop() {
|
|
42
|
+
this.onExit(0);
|
|
43
|
+
process.exit();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.default = ProcessChild;
|
|
47
|
+
// @ts-expect-error TS2345
|
|
48
|
+
(0, childState_1.setChild)(new child_1.Child(ProcessChild));
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.WORKER_PATH = void 0;
|
|
7
|
+
const child_process_1 = __importDefault(require("child_process"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const build_cache_1 = require("@atlaspack/build-cache");
|
|
10
|
+
exports.WORKER_PATH = path_1.default.join(__dirname, 'ProcessChild.js');
|
|
11
|
+
if (process.env.ATLASPACK_REGISTER_USE_SRC === 'true') {
|
|
12
|
+
exports.WORKER_PATH = path_1.default.join(__dirname, 'ProcessChild.ts');
|
|
13
|
+
}
|
|
14
|
+
// @ts-expect-error TS2420
|
|
15
|
+
class ProcessWorker {
|
|
16
|
+
constructor(execArgv, onMessage, onError, onExit) {
|
|
17
|
+
this.processQueue = true;
|
|
18
|
+
this.sendQueue = [];
|
|
19
|
+
this.execArgv = execArgv;
|
|
20
|
+
this.onMessage = onMessage;
|
|
21
|
+
this.onError = onError;
|
|
22
|
+
this.onExit = onExit;
|
|
23
|
+
}
|
|
24
|
+
start() {
|
|
25
|
+
this.child = child_process_1.default.fork(exports.WORKER_PATH, process.argv, {
|
|
26
|
+
execArgv: this.execArgv,
|
|
27
|
+
env: process.env,
|
|
28
|
+
cwd: process.cwd(),
|
|
29
|
+
});
|
|
30
|
+
this.child.on('message', (data) => {
|
|
31
|
+
this.onMessage((0, build_cache_1.deserialize)(Buffer.from(data, 'base64')));
|
|
32
|
+
});
|
|
33
|
+
this.child.once('exit', this.onExit);
|
|
34
|
+
this.child.on('error', this.onError);
|
|
35
|
+
return Promise.resolve();
|
|
36
|
+
}
|
|
37
|
+
async stop() {
|
|
38
|
+
this.child.send('die');
|
|
39
|
+
let forceKill = setTimeout(() => this.child.kill('SIGINT'), 500);
|
|
40
|
+
await new Promise((resolve) => {
|
|
41
|
+
this.child.once('exit', resolve);
|
|
42
|
+
});
|
|
43
|
+
clearTimeout(forceKill);
|
|
44
|
+
}
|
|
45
|
+
send(data) {
|
|
46
|
+
if (!this.processQueue) {
|
|
47
|
+
this.sendQueue.push(data);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
let result = this.child.send((0, build_cache_1.serialize)(data).toString('base64'), (error) => {
|
|
51
|
+
if (error && error instanceof Error) {
|
|
52
|
+
// Ignore this, the workerfarm handles child errors
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.processQueue = true;
|
|
56
|
+
if (this.sendQueue.length > 0) {
|
|
57
|
+
let queueCopy = this.sendQueue.slice(0);
|
|
58
|
+
this.sendQueue = [];
|
|
59
|
+
queueCopy.forEach((entry) => this.send(entry));
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
if (!result || /^win/.test(process.platform)) {
|
|
63
|
+
// Queue is handling too much messages throttle it
|
|
64
|
+
this.processQueue = false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.default = ProcessWorker;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const worker_threads_1 = require("worker_threads");
|
|
7
|
+
const build_cache_1 = require("@atlaspack/build-cache");
|
|
8
|
+
const nullthrows_1 = __importDefault(require("nullthrows"));
|
|
9
|
+
const child_1 = require("../child");
|
|
10
|
+
const childState_1 = require("../childState");
|
|
11
|
+
// @ts-expect-error TS2420
|
|
12
|
+
class ThreadsChild {
|
|
13
|
+
constructor(onMessage, onExit) {
|
|
14
|
+
if (worker_threads_1.isMainThread || !worker_threads_1.parentPort) {
|
|
15
|
+
throw new Error('Only create ThreadsChild instances in a worker!');
|
|
16
|
+
}
|
|
17
|
+
this.onMessage = onMessage;
|
|
18
|
+
this.onExit = onExit;
|
|
19
|
+
worker_threads_1.parentPort.on('message', (data) => this.handleMessage(data));
|
|
20
|
+
worker_threads_1.parentPort.on('close', this.onExit);
|
|
21
|
+
}
|
|
22
|
+
handleMessage(data) {
|
|
23
|
+
this.onMessage((0, build_cache_1.restoreDeserializedObject)(data));
|
|
24
|
+
}
|
|
25
|
+
send(data) {
|
|
26
|
+
(0, nullthrows_1.default)(worker_threads_1.parentPort).postMessage((0, build_cache_1.prepareForSerialization)(data));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.default = ThreadsChild;
|
|
30
|
+
// @ts-expect-error TS2345
|
|
31
|
+
(0, childState_1.setChild)(new child_1.Child(ThreadsChild));
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.WORKER_PATH = void 0;
|
|
7
|
+
const worker_threads_1 = require("worker_threads");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const build_cache_1 = require("@atlaspack/build-cache");
|
|
10
|
+
exports.WORKER_PATH = path_1.default.join(__dirname, 'ThreadsChild.js');
|
|
11
|
+
if (process.env.ATLASPACK_REGISTER_USE_SRC === 'true') {
|
|
12
|
+
exports.WORKER_PATH = path_1.default.join(__dirname, 'ThreadsChild.ts');
|
|
13
|
+
}
|
|
14
|
+
// @ts-expect-error TS2420
|
|
15
|
+
class ThreadsWorker {
|
|
16
|
+
constructor(execArgv, onMessage, onError, onExit) {
|
|
17
|
+
this.execArgv = execArgv;
|
|
18
|
+
this.onMessage = onMessage;
|
|
19
|
+
this.onError = onError;
|
|
20
|
+
this.onExit = onExit;
|
|
21
|
+
}
|
|
22
|
+
start() {
|
|
23
|
+
this.worker = new worker_threads_1.Worker(exports.WORKER_PATH, {
|
|
24
|
+
execArgv: this.execArgv,
|
|
25
|
+
env: process.env,
|
|
26
|
+
});
|
|
27
|
+
this.worker.on('message', (data) => this.handleMessage(data));
|
|
28
|
+
this.worker.on('error', this.onError);
|
|
29
|
+
this.worker.on('exit', this.onExit);
|
|
30
|
+
return new Promise((resolve) => {
|
|
31
|
+
this.worker.on('online', resolve);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
stop() {
|
|
35
|
+
// In node 12, this returns a promise, but previously it accepted a callback
|
|
36
|
+
// TODO: Pass a callback in earlier versions of Node
|
|
37
|
+
// @ts-expect-error TS2322
|
|
38
|
+
return Promise.resolve(this.worker.terminate());
|
|
39
|
+
}
|
|
40
|
+
handleMessage(data) {
|
|
41
|
+
this.onMessage((0, build_cache_1.restoreDeserializedObject)(data));
|
|
42
|
+
}
|
|
43
|
+
send(data) {
|
|
44
|
+
this.worker.postMessage((0, build_cache_1.prepareForSerialization)(data));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.default = ThreadsWorker;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-env worker*/
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const build_cache_1 = require("@atlaspack/build-cache");
|
|
5
|
+
const child_1 = require("../child");
|
|
6
|
+
const childState_1 = require("../childState");
|
|
7
|
+
// @ts-expect-error TS2420
|
|
8
|
+
class WebChild {
|
|
9
|
+
constructor(onMessage, onExit) {
|
|
10
|
+
if (!(typeof WorkerGlobalScope !== 'undefined' &&
|
|
11
|
+
self instanceof WorkerGlobalScope)) {
|
|
12
|
+
throw new Error('Only create WebChild instances in a worker!');
|
|
13
|
+
}
|
|
14
|
+
this.onMessage = onMessage;
|
|
15
|
+
this.onExit = onExit;
|
|
16
|
+
self.addEventListener('message', ({ data }) => {
|
|
17
|
+
if (data === 'stop') {
|
|
18
|
+
this.onExit(0);
|
|
19
|
+
self.postMessage('stopped');
|
|
20
|
+
}
|
|
21
|
+
this.handleMessage(data);
|
|
22
|
+
});
|
|
23
|
+
self.postMessage('online');
|
|
24
|
+
}
|
|
25
|
+
handleMessage(data) {
|
|
26
|
+
this.onMessage((0, build_cache_1.restoreDeserializedObject)(data));
|
|
27
|
+
}
|
|
28
|
+
send(data) {
|
|
29
|
+
self.postMessage((0, build_cache_1.prepareForSerialization)(data));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.default = WebChild;
|
|
33
|
+
// @ts-expect-error TS2345
|
|
34
|
+
(0, childState_1.setChild)(new child_1.Child(WebChild));
|