@xylabs/threads 3.6.6 → 3.6.8
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/dist/esm/master/implementation.browser.js +3 -3
- package/dist/esm/master/implementation.node.js +11 -9
- package/dist/esm/master/pool.js +9 -9
- package/dist/esm/master/spawn.js +4 -4
- package/dist/esm/observable-promise.js +2 -2
- package/dist/esm/observable.js +1 -1
- package/dist/esm/worker/index.js +2 -2
- package/dist/master/implementation.browser.js +3 -3
- package/dist/master/implementation.node.js +11 -9
- package/dist/master/pool.js +9 -9
- package/dist/master/spawn.js +4 -4
- package/dist/observable-promise.js +2 -2
- package/dist/observable.js +1 -1
- package/dist/worker/index.js +2 -2
- package/observable.d.ts +1 -0
- package/package.json +6 -6
- package/register.d.ts +1 -0
- package/rollup.config.js +0 -1
- package/src/index.ts +1 -0
- package/src/master/implementation.browser.ts +4 -3
- package/src/master/implementation.node.ts +20 -17
- package/src/master/index.ts +1 -0
- package/src/master/invocation-proxy.ts +1 -1
- package/src/master/pool-types.ts +28 -28
- package/src/master/pool.ts +10 -10
- package/src/master/spawn.ts +10 -9
- package/src/master/thread.ts +1 -0
- package/src/observable-promise.ts +11 -11
- package/src/observable.ts +1 -2
- package/src/ponyfills.ts +6 -6
- package/src/serializers.ts +1 -0
- package/src/transferable.ts +0 -1
- package/src/types/master.ts +4 -3
- package/src/worker/implementation.browser.ts +1 -0
- package/src/worker/implementation.tiny-worker.ts +1 -1
- package/src/worker/implementation.ts +1 -0
- package/src/worker/implementation.worker_threads.ts +1 -0
- package/src/worker/index.ts +3 -2
- package/test/lib/serialization.ts +2 -2
- package/test/observable-promise.test.ts +9 -9
- package/test/observable.test.ts +7 -6
- package/test/pool.test.ts +7 -7
- package/test/serialization.test.ts +1 -0
- package/test/spawn.chromium.mocha.ts +1 -0
- package/test/spawn.test.ts +4 -2
- package/test/streaming.test.ts +1 -1
- package/test/transferables.test.ts +3 -2
- package/test/workers/minmax.ts +1 -0
- package/test/workers/serialization.ts +1 -0
- package/test-tooling/webpack/app.ts +4 -5
- package/test-tooling/webpack/webpack.chromium.mocha.ts +1 -1
- package/test-tooling/webpack/webpack.node.config.js +0 -1
- package/test-tooling/webpack/webpack.test.ts +13 -7
- package/test-tooling/webpack/webpack.web.config.js +0 -1
- package/worker.d.ts +1 -0
|
@@ -29,9 +29,9 @@ function selectWorkerImplementation() {
|
|
|
29
29
|
url = createSourceBlobURL(`importScripts(${JSON.stringify(url)});`);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
if (typeof url === 'string'
|
|
33
|
-
isAbsoluteURL(url)
|
|
34
|
-
(options?.CORSWorkaround ?? true)) {
|
|
32
|
+
if (typeof url === 'string'
|
|
33
|
+
&& isAbsoluteURL(url)
|
|
34
|
+
&& (options?.CORSWorkaround ?? true)) {
|
|
35
35
|
url = createSourceBlobURL(`importScripts(${JSON.stringify(url)});`);
|
|
36
36
|
}
|
|
37
37
|
super(url, options);
|
|
@@ -56,8 +56,8 @@ function resolveScriptPath(scriptPath, baseURL) {
|
|
|
56
56
|
const makeRelative = (filePath) => {
|
|
57
57
|
return node_path_1.default.isAbsolute(filePath) ? filePath : node_path_1.default.join(baseURL || eval('__dirname'), filePath);
|
|
58
58
|
};
|
|
59
|
-
return typeof __non_webpack_require__ === 'function'
|
|
60
|
-
__non_webpack_require__.resolve(makeRelative(scriptPath))
|
|
59
|
+
return typeof __non_webpack_require__ === 'function'
|
|
60
|
+
? __non_webpack_require__.resolve(makeRelative(scriptPath))
|
|
61
61
|
: eval('require').resolve(makeRelative(rebaseScriptPath(scriptPath, /[/\\]worker_threads[/\\]/)));
|
|
62
62
|
}
|
|
63
63
|
function initWorkerThreadsWorker() {
|
|
@@ -96,7 +96,7 @@ function initWorkerThreadsWorker() {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
const terminateWorkersAndMaster = () => {
|
|
99
|
-
Promise.all(allWorkers.map(
|
|
99
|
+
Promise.all(allWorkers.map(worker => worker.terminate())).then(() => process.exit(0), () => process.exit(1));
|
|
100
100
|
allWorkers = [];
|
|
101
101
|
};
|
|
102
102
|
process.on('SIGINT', () => terminateWorkersAndMaster());
|
|
@@ -120,8 +120,10 @@ function initTinyWorker() {
|
|
|
120
120
|
class Worker extends TinyWorker {
|
|
121
121
|
emitter;
|
|
122
122
|
constructor(scriptPath, options) {
|
|
123
|
-
const resolvedScriptPath = options && options.fromSource
|
|
124
|
-
|
|
123
|
+
const resolvedScriptPath = options && options.fromSource
|
|
124
|
+
? null
|
|
125
|
+
: process.platform === 'win32'
|
|
126
|
+
? `file:///${resolveScriptPath(scriptPath).replaceAll('\\', '/')}`
|
|
125
127
|
: resolveScriptPath(scriptPath);
|
|
126
128
|
if (!resolvedScriptPath) {
|
|
127
129
|
const sourceCode = scriptPath;
|
|
@@ -148,12 +150,12 @@ function initTinyWorker() {
|
|
|
148
150
|
this.emitter.removeListener(eventName, listener);
|
|
149
151
|
}
|
|
150
152
|
terminate() {
|
|
151
|
-
allWorkers = allWorkers.filter(
|
|
153
|
+
allWorkers = allWorkers.filter(worker => worker !== this);
|
|
152
154
|
return super.terminate();
|
|
153
155
|
}
|
|
154
156
|
}
|
|
155
157
|
const terminateWorkersAndMaster = () => {
|
|
156
|
-
Promise.all(allWorkers.map(
|
|
158
|
+
Promise.all(allWorkers.map(worker => worker.terminate())).then(() => process.exit(0), () => process.exit(1));
|
|
157
159
|
allWorkers = [];
|
|
158
160
|
};
|
|
159
161
|
process.on('SIGINT', () => terminateWorkersAndMaster());
|
|
@@ -195,8 +197,8 @@ function isWorkerRuntime() {
|
|
|
195
197
|
return self !== undefined && self['postMessage'] ? true : false;
|
|
196
198
|
}
|
|
197
199
|
else {
|
|
198
|
-
const isMainThread = typeof __non_webpack_require__ === 'function'
|
|
199
|
-
__non_webpack_require__('worker_threads').isMainThread
|
|
200
|
+
const isMainThread = typeof __non_webpack_require__ === 'function'
|
|
201
|
+
? __non_webpack_require__('worker_threads').isMainThread
|
|
200
202
|
: eval('require')('worker_threads').isMainThread;
|
|
201
203
|
return !isMainThread;
|
|
202
204
|
}
|
package/dist/esm/master/pool.js
CHANGED
|
@@ -19,7 +19,7 @@ function createArray(size) {
|
|
|
19
19
|
return array;
|
|
20
20
|
}
|
|
21
21
|
function delay(ms) {
|
|
22
|
-
return new Promise(
|
|
22
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
23
23
|
}
|
|
24
24
|
function flatMap(array, mapper) {
|
|
25
25
|
return array.reduce((flattened, element) => [...flattened, ...mapper(element)], []);
|
|
@@ -51,7 +51,7 @@ class WorkerPool {
|
|
|
51
51
|
this.options = options;
|
|
52
52
|
this.workers = spawnWorkers(spawnWorker, size);
|
|
53
53
|
this.eventObservable = (0, observable_fns_1.multicast)(observable_fns_1.Observable.from(this.eventSubject));
|
|
54
|
-
Promise.all(this.workers.map(
|
|
54
|
+
Promise.all(this.workers.map(worker => worker.init)).then(() => this.eventSubject.next({
|
|
55
55
|
size: this.workers.length,
|
|
56
56
|
type: pool_types_1.PoolEventType.initialized,
|
|
57
57
|
}), (error) => {
|
|
@@ -62,7 +62,7 @@ class WorkerPool {
|
|
|
62
62
|
}
|
|
63
63
|
findIdlingWorker() {
|
|
64
64
|
const { concurrency = 1 } = this.options;
|
|
65
|
-
return this.workers.find(
|
|
65
|
+
return this.workers.find(worker => worker.runningTasks.length < concurrency);
|
|
66
66
|
}
|
|
67
67
|
async runPoolTask(worker, task) {
|
|
68
68
|
const workerID = this.workers.indexOf(worker) + 1;
|
|
@@ -95,7 +95,7 @@ class WorkerPool {
|
|
|
95
95
|
async run(worker, task) {
|
|
96
96
|
const runPromise = (async () => {
|
|
97
97
|
const removeTaskFromWorkersRunningTasks = () => {
|
|
98
|
-
worker.runningTasks = worker.runningTasks.filter(
|
|
98
|
+
worker.runningTasks = worker.runningTasks.filter(someRunPromise => someRunPromise !== runPromise);
|
|
99
99
|
};
|
|
100
100
|
await delay(0);
|
|
101
101
|
try {
|
|
@@ -142,7 +142,7 @@ class WorkerPool {
|
|
|
142
142
|
});
|
|
143
143
|
}
|
|
144
144
|
async settled(allowResolvingImmediately = false) {
|
|
145
|
-
const getCurrentlyRunningTasks = () => flatMap(this.workers,
|
|
145
|
+
const getCurrentlyRunningTasks = () => flatMap(this.workers, worker => worker.runningTasks);
|
|
146
146
|
const taskFailures = [];
|
|
147
147
|
const failureSubscription = this.eventObservable.subscribe((event) => {
|
|
148
148
|
if (event.type === pool_types_1.PoolEventType.taskFailed) {
|
|
@@ -213,7 +213,7 @@ class WorkerPool {
|
|
|
213
213
|
cancel: () => {
|
|
214
214
|
if (!this.taskQueue.includes(task))
|
|
215
215
|
return;
|
|
216
|
-
this.taskQueue = this.taskQueue.filter(
|
|
216
|
+
this.taskQueue = this.taskQueue.filter(someTask => someTask !== task);
|
|
217
217
|
this.eventSubject.next({
|
|
218
218
|
taskID: task.id,
|
|
219
219
|
type: pool_types_1.PoolEventType.taskCanceled,
|
|
@@ -224,9 +224,9 @@ class WorkerPool {
|
|
|
224
224
|
then: taskCompletion.then.bind(taskCompletion),
|
|
225
225
|
};
|
|
226
226
|
if (this.taskQueue.length >= maxQueuedJobs) {
|
|
227
|
-
throw new Error('Maximum number of pool tasks queued. Refusing to queue another one.\n'
|
|
228
|
-
'This usually happens for one of two reasons: We are either at peak '
|
|
229
|
-
"workload right now or some tasks just won't finish, thus blocking the pool.");
|
|
227
|
+
throw new Error('Maximum number of pool tasks queued. Refusing to queue another one.\n'
|
|
228
|
+
+ 'This usually happens for one of two reasons: We are either at peak '
|
|
229
|
+
+ "workload right now or some tasks just won't finish, thus blocking the pool.");
|
|
230
230
|
}
|
|
231
231
|
this.debug(`Queueing task #${task.id}...`);
|
|
232
232
|
this.taskQueue.push(task);
|
package/dist/esm/master/spawn.js
CHANGED
|
@@ -16,8 +16,8 @@ const debugSpawn = (0, debug_1.default)('threads:master:spawn');
|
|
|
16
16
|
const debugThreadUtils = (0, debug_1.default)('threads:master:thread-utils');
|
|
17
17
|
const isInitMessage = (data) => data && data.type === 'init';
|
|
18
18
|
const isUncaughtErrorMessage = (data) => data && data.type === 'uncaughtError';
|
|
19
|
-
const initMessageTimeout = typeof process !== 'undefined' && process.env !== undefined && process.env.THREADS_WORKER_INIT_TIMEOUT
|
|
20
|
-
Number.parseInt(process.env.THREADS_WORKER_INIT_TIMEOUT, 10)
|
|
19
|
+
const initMessageTimeout = typeof process !== 'undefined' && process.env !== undefined && process.env.THREADS_WORKER_INIT_TIMEOUT
|
|
20
|
+
? Number.parseInt(process.env.THREADS_WORKER_INIT_TIMEOUT, 10)
|
|
21
21
|
: 10_000;
|
|
22
22
|
async function withTimeout(promise, timeoutInMs, errorMessage) {
|
|
23
23
|
let timeoutHandle;
|
|
@@ -85,8 +85,8 @@ function createTerminator(worker) {
|
|
|
85
85
|
}
|
|
86
86
|
function setPrivateThreadProps(raw, worker, workerEvents, terminate) {
|
|
87
87
|
const workerErrors = workerEvents
|
|
88
|
-
.filter(
|
|
89
|
-
.map(
|
|
88
|
+
.filter(event => event.type === master_1.WorkerEventType.internalError)
|
|
89
|
+
.map(errorEvent => errorEvent.error);
|
|
90
90
|
return Object.assign(raw, {
|
|
91
91
|
[symbols_1.$errors]: workerErrors,
|
|
92
92
|
[symbols_1.$events]: workerEvents,
|
|
@@ -115,8 +115,8 @@ class ObservablePromise extends observable_fns_1.Observable {
|
|
|
115
115
|
}, () => handler());
|
|
116
116
|
}
|
|
117
117
|
static from(thing) {
|
|
118
|
-
return isThenable(thing)
|
|
119
|
-
new ObservablePromise((observer) => {
|
|
118
|
+
return isThenable(thing)
|
|
119
|
+
? new ObservablePromise((observer) => {
|
|
120
120
|
const onFulfilled = (value) => {
|
|
121
121
|
observer.next(value);
|
|
122
122
|
observer.complete();
|
package/dist/esm/observable.js
CHANGED
|
@@ -9,7 +9,7 @@ class Subject extends observable_fns_1.Observable {
|
|
|
9
9
|
super((observer) => {
|
|
10
10
|
this[$observers] = [...(this[$observers] || []), observer];
|
|
11
11
|
const unsubscribe = () => {
|
|
12
|
-
this[$observers] = this[$observers].filter(
|
|
12
|
+
this[$observers] = this[$observers].filter(someObserver => someObserver !== observer);
|
|
13
13
|
};
|
|
14
14
|
return unsubscribe;
|
|
15
15
|
});
|
package/dist/esm/worker/index.js
CHANGED
|
@@ -95,7 +95,7 @@ async function runFunction(jobUID, fn, args) {
|
|
|
95
95
|
const resultType = isObservable(syncResult) ? 'observable' : 'promise';
|
|
96
96
|
postJobStartMessage(jobUID, resultType);
|
|
97
97
|
if (isObservable(syncResult)) {
|
|
98
|
-
const subscription = syncResult.subscribe(
|
|
98
|
+
const subscription = syncResult.subscribe(value => postJobResultMessage(jobUID, false, (0, common_1.serialize)(value)), (error) => {
|
|
99
99
|
postJobErrorMessage(jobUID, (0, common_1.serialize)(error));
|
|
100
100
|
activeSubscriptions.delete(jobUID);
|
|
101
101
|
}, () => {
|
|
@@ -136,7 +136,7 @@ function expose(exposed) {
|
|
|
136
136
|
runFunction(messageData.uid, exposed[messageData.method], messageData.args.map(common_1.deserialize));
|
|
137
137
|
}
|
|
138
138
|
});
|
|
139
|
-
const methodNames = Object.keys(exposed).filter(
|
|
139
|
+
const methodNames = Object.keys(exposed).filter(key => typeof exposed[key] === 'function');
|
|
140
140
|
postModuleInitMessage(methodNames);
|
|
141
141
|
}
|
|
142
142
|
else {
|
|
@@ -29,9 +29,9 @@ function selectWorkerImplementation() {
|
|
|
29
29
|
url = createSourceBlobURL(`importScripts(${JSON.stringify(url)});`);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
if (typeof url === 'string'
|
|
33
|
-
isAbsoluteURL(url)
|
|
34
|
-
(options?.CORSWorkaround ?? true)) {
|
|
32
|
+
if (typeof url === 'string'
|
|
33
|
+
&& isAbsoluteURL(url)
|
|
34
|
+
&& (options?.CORSWorkaround ?? true)) {
|
|
35
35
|
url = createSourceBlobURL(`importScripts(${JSON.stringify(url)});`);
|
|
36
36
|
}
|
|
37
37
|
super(url, options);
|
|
@@ -56,8 +56,8 @@ function resolveScriptPath(scriptPath, baseURL) {
|
|
|
56
56
|
const makeRelative = (filePath) => {
|
|
57
57
|
return node_path_1.default.isAbsolute(filePath) ? filePath : node_path_1.default.join(baseURL || eval('__dirname'), filePath);
|
|
58
58
|
};
|
|
59
|
-
return typeof __non_webpack_require__ === 'function'
|
|
60
|
-
__non_webpack_require__.resolve(makeRelative(scriptPath))
|
|
59
|
+
return typeof __non_webpack_require__ === 'function'
|
|
60
|
+
? __non_webpack_require__.resolve(makeRelative(scriptPath))
|
|
61
61
|
: eval('require').resolve(makeRelative(rebaseScriptPath(scriptPath, /[/\\]worker_threads[/\\]/)));
|
|
62
62
|
}
|
|
63
63
|
function initWorkerThreadsWorker() {
|
|
@@ -96,7 +96,7 @@ function initWorkerThreadsWorker() {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
const terminateWorkersAndMaster = () => {
|
|
99
|
-
Promise.all(allWorkers.map(
|
|
99
|
+
Promise.all(allWorkers.map(worker => worker.terminate())).then(() => process.exit(0), () => process.exit(1));
|
|
100
100
|
allWorkers = [];
|
|
101
101
|
};
|
|
102
102
|
process.on('SIGINT', () => terminateWorkersAndMaster());
|
|
@@ -120,8 +120,10 @@ function initTinyWorker() {
|
|
|
120
120
|
class Worker extends TinyWorker {
|
|
121
121
|
emitter;
|
|
122
122
|
constructor(scriptPath, options) {
|
|
123
|
-
const resolvedScriptPath = options && options.fromSource
|
|
124
|
-
|
|
123
|
+
const resolvedScriptPath = options && options.fromSource
|
|
124
|
+
? null
|
|
125
|
+
: process.platform === 'win32'
|
|
126
|
+
? `file:///${resolveScriptPath(scriptPath).replaceAll('\\', '/')}`
|
|
125
127
|
: resolveScriptPath(scriptPath);
|
|
126
128
|
if (!resolvedScriptPath) {
|
|
127
129
|
const sourceCode = scriptPath;
|
|
@@ -148,12 +150,12 @@ function initTinyWorker() {
|
|
|
148
150
|
this.emitter.removeListener(eventName, listener);
|
|
149
151
|
}
|
|
150
152
|
terminate() {
|
|
151
|
-
allWorkers = allWorkers.filter(
|
|
153
|
+
allWorkers = allWorkers.filter(worker => worker !== this);
|
|
152
154
|
return super.terminate();
|
|
153
155
|
}
|
|
154
156
|
}
|
|
155
157
|
const terminateWorkersAndMaster = () => {
|
|
156
|
-
Promise.all(allWorkers.map(
|
|
158
|
+
Promise.all(allWorkers.map(worker => worker.terminate())).then(() => process.exit(0), () => process.exit(1));
|
|
157
159
|
allWorkers = [];
|
|
158
160
|
};
|
|
159
161
|
process.on('SIGINT', () => terminateWorkersAndMaster());
|
|
@@ -195,8 +197,8 @@ function isWorkerRuntime() {
|
|
|
195
197
|
return self !== undefined && self['postMessage'] ? true : false;
|
|
196
198
|
}
|
|
197
199
|
else {
|
|
198
|
-
const isMainThread = typeof __non_webpack_require__ === 'function'
|
|
199
|
-
__non_webpack_require__('worker_threads').isMainThread
|
|
200
|
+
const isMainThread = typeof __non_webpack_require__ === 'function'
|
|
201
|
+
? __non_webpack_require__('worker_threads').isMainThread
|
|
200
202
|
: eval('require')('worker_threads').isMainThread;
|
|
201
203
|
return !isMainThread;
|
|
202
204
|
}
|
package/dist/master/pool.js
CHANGED
|
@@ -19,7 +19,7 @@ function createArray(size) {
|
|
|
19
19
|
return array;
|
|
20
20
|
}
|
|
21
21
|
function delay(ms) {
|
|
22
|
-
return new Promise(
|
|
22
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
23
23
|
}
|
|
24
24
|
function flatMap(array, mapper) {
|
|
25
25
|
return array.reduce((flattened, element) => [...flattened, ...mapper(element)], []);
|
|
@@ -51,7 +51,7 @@ class WorkerPool {
|
|
|
51
51
|
this.options = options;
|
|
52
52
|
this.workers = spawnWorkers(spawnWorker, size);
|
|
53
53
|
this.eventObservable = (0, observable_fns_1.multicast)(observable_fns_1.Observable.from(this.eventSubject));
|
|
54
|
-
Promise.all(this.workers.map(
|
|
54
|
+
Promise.all(this.workers.map(worker => worker.init)).then(() => this.eventSubject.next({
|
|
55
55
|
size: this.workers.length,
|
|
56
56
|
type: pool_types_1.PoolEventType.initialized,
|
|
57
57
|
}), (error) => {
|
|
@@ -62,7 +62,7 @@ class WorkerPool {
|
|
|
62
62
|
}
|
|
63
63
|
findIdlingWorker() {
|
|
64
64
|
const { concurrency = 1 } = this.options;
|
|
65
|
-
return this.workers.find(
|
|
65
|
+
return this.workers.find(worker => worker.runningTasks.length < concurrency);
|
|
66
66
|
}
|
|
67
67
|
async runPoolTask(worker, task) {
|
|
68
68
|
const workerID = this.workers.indexOf(worker) + 1;
|
|
@@ -95,7 +95,7 @@ class WorkerPool {
|
|
|
95
95
|
async run(worker, task) {
|
|
96
96
|
const runPromise = (async () => {
|
|
97
97
|
const removeTaskFromWorkersRunningTasks = () => {
|
|
98
|
-
worker.runningTasks = worker.runningTasks.filter(
|
|
98
|
+
worker.runningTasks = worker.runningTasks.filter(someRunPromise => someRunPromise !== runPromise);
|
|
99
99
|
};
|
|
100
100
|
await delay(0);
|
|
101
101
|
try {
|
|
@@ -142,7 +142,7 @@ class WorkerPool {
|
|
|
142
142
|
});
|
|
143
143
|
}
|
|
144
144
|
async settled(allowResolvingImmediately = false) {
|
|
145
|
-
const getCurrentlyRunningTasks = () => flatMap(this.workers,
|
|
145
|
+
const getCurrentlyRunningTasks = () => flatMap(this.workers, worker => worker.runningTasks);
|
|
146
146
|
const taskFailures = [];
|
|
147
147
|
const failureSubscription = this.eventObservable.subscribe((event) => {
|
|
148
148
|
if (event.type === pool_types_1.PoolEventType.taskFailed) {
|
|
@@ -213,7 +213,7 @@ class WorkerPool {
|
|
|
213
213
|
cancel: () => {
|
|
214
214
|
if (!this.taskQueue.includes(task))
|
|
215
215
|
return;
|
|
216
|
-
this.taskQueue = this.taskQueue.filter(
|
|
216
|
+
this.taskQueue = this.taskQueue.filter(someTask => someTask !== task);
|
|
217
217
|
this.eventSubject.next({
|
|
218
218
|
taskID: task.id,
|
|
219
219
|
type: pool_types_1.PoolEventType.taskCanceled,
|
|
@@ -224,9 +224,9 @@ class WorkerPool {
|
|
|
224
224
|
then: taskCompletion.then.bind(taskCompletion),
|
|
225
225
|
};
|
|
226
226
|
if (this.taskQueue.length >= maxQueuedJobs) {
|
|
227
|
-
throw new Error('Maximum number of pool tasks queued. Refusing to queue another one.\n'
|
|
228
|
-
'This usually happens for one of two reasons: We are either at peak '
|
|
229
|
-
"workload right now or some tasks just won't finish, thus blocking the pool.");
|
|
227
|
+
throw new Error('Maximum number of pool tasks queued. Refusing to queue another one.\n'
|
|
228
|
+
+ 'This usually happens for one of two reasons: We are either at peak '
|
|
229
|
+
+ "workload right now or some tasks just won't finish, thus blocking the pool.");
|
|
230
230
|
}
|
|
231
231
|
this.debug(`Queueing task #${task.id}...`);
|
|
232
232
|
this.taskQueue.push(task);
|
package/dist/master/spawn.js
CHANGED
|
@@ -16,8 +16,8 @@ const debugSpawn = (0, debug_1.default)('threads:master:spawn');
|
|
|
16
16
|
const debugThreadUtils = (0, debug_1.default)('threads:master:thread-utils');
|
|
17
17
|
const isInitMessage = (data) => data && data.type === 'init';
|
|
18
18
|
const isUncaughtErrorMessage = (data) => data && data.type === 'uncaughtError';
|
|
19
|
-
const initMessageTimeout = typeof process !== 'undefined' && process.env !== undefined && process.env.THREADS_WORKER_INIT_TIMEOUT
|
|
20
|
-
Number.parseInt(process.env.THREADS_WORKER_INIT_TIMEOUT, 10)
|
|
19
|
+
const initMessageTimeout = typeof process !== 'undefined' && process.env !== undefined && process.env.THREADS_WORKER_INIT_TIMEOUT
|
|
20
|
+
? Number.parseInt(process.env.THREADS_WORKER_INIT_TIMEOUT, 10)
|
|
21
21
|
: 10_000;
|
|
22
22
|
async function withTimeout(promise, timeoutInMs, errorMessage) {
|
|
23
23
|
let timeoutHandle;
|
|
@@ -85,8 +85,8 @@ function createTerminator(worker) {
|
|
|
85
85
|
}
|
|
86
86
|
function setPrivateThreadProps(raw, worker, workerEvents, terminate) {
|
|
87
87
|
const workerErrors = workerEvents
|
|
88
|
-
.filter(
|
|
89
|
-
.map(
|
|
88
|
+
.filter(event => event.type === master_1.WorkerEventType.internalError)
|
|
89
|
+
.map(errorEvent => errorEvent.error);
|
|
90
90
|
return Object.assign(raw, {
|
|
91
91
|
[symbols_1.$errors]: workerErrors,
|
|
92
92
|
[symbols_1.$events]: workerEvents,
|
|
@@ -115,8 +115,8 @@ class ObservablePromise extends observable_fns_1.Observable {
|
|
|
115
115
|
}, () => handler());
|
|
116
116
|
}
|
|
117
117
|
static from(thing) {
|
|
118
|
-
return isThenable(thing)
|
|
119
|
-
new ObservablePromise((observer) => {
|
|
118
|
+
return isThenable(thing)
|
|
119
|
+
? new ObservablePromise((observer) => {
|
|
120
120
|
const onFulfilled = (value) => {
|
|
121
121
|
observer.next(value);
|
|
122
122
|
observer.complete();
|
package/dist/observable.js
CHANGED
|
@@ -9,7 +9,7 @@ class Subject extends observable_fns_1.Observable {
|
|
|
9
9
|
super((observer) => {
|
|
10
10
|
this[$observers] = [...(this[$observers] || []), observer];
|
|
11
11
|
const unsubscribe = () => {
|
|
12
|
-
this[$observers] = this[$observers].filter(
|
|
12
|
+
this[$observers] = this[$observers].filter(someObserver => someObserver !== observer);
|
|
13
13
|
};
|
|
14
14
|
return unsubscribe;
|
|
15
15
|
});
|
package/dist/worker/index.js
CHANGED
|
@@ -95,7 +95,7 @@ async function runFunction(jobUID, fn, args) {
|
|
|
95
95
|
const resultType = isObservable(syncResult) ? 'observable' : 'promise';
|
|
96
96
|
postJobStartMessage(jobUID, resultType);
|
|
97
97
|
if (isObservable(syncResult)) {
|
|
98
|
-
const subscription = syncResult.subscribe(
|
|
98
|
+
const subscription = syncResult.subscribe(value => postJobResultMessage(jobUID, false, (0, common_1.serialize)(value)), (error) => {
|
|
99
99
|
postJobErrorMessage(jobUID, (0, common_1.serialize)(error));
|
|
100
100
|
activeSubscriptions.delete(jobUID);
|
|
101
101
|
}, () => {
|
|
@@ -136,7 +136,7 @@ function expose(exposed) {
|
|
|
136
136
|
runFunction(messageData.uid, exposed[messageData.method], messageData.args.map(common_1.deserialize));
|
|
137
137
|
}
|
|
138
138
|
});
|
|
139
|
-
const methodNames = Object.keys(exposed).filter(
|
|
139
|
+
const methodNames = Object.keys(exposed).filter(key => typeof exposed[key] === 'function');
|
|
140
140
|
postModuleInitMessage(methodNames);
|
|
141
141
|
}
|
|
142
142
|
else {
|
package/observable.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xylabs/threads",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.8",
|
|
4
4
|
"description": "Web workers & worker threads as simple as a function call",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/esm/index.js",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"package-compile": "yarn build",
|
|
10
|
-
"clean": "rimraf dist
|
|
10
|
+
"clean": "rimraf ./dist ./dist-esm",
|
|
11
11
|
"dev": "npm run clean && tsc -p tsconfig.json --watch",
|
|
12
12
|
"build": "npm run clean && npm run build:cjs && npm run build:es",
|
|
13
13
|
"build:cjs": "tsc -p tsconfig.json",
|
|
@@ -92,10 +92,10 @@
|
|
|
92
92
|
"devDependencies": {
|
|
93
93
|
"@rollup/plugin-commonjs": "^26.0.1",
|
|
94
94
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
95
|
-
"@types/chai": "^4.3.
|
|
95
|
+
"@types/chai": "^4.3.17",
|
|
96
96
|
"@types/debug": "^4.1.12",
|
|
97
97
|
"@types/execa": "^2.0.0",
|
|
98
|
-
"@types/node": "^22.
|
|
98
|
+
"@types/node": "^22.1.0",
|
|
99
99
|
"@types/webpack": "^5.28.5",
|
|
100
100
|
"ava": "^6.1.3",
|
|
101
101
|
"chai": "^5.1.1",
|
|
@@ -105,8 +105,8 @@
|
|
|
105
105
|
"puppet-run": "^0.11.4",
|
|
106
106
|
"puppet-run-plugin-mocha": "^0.1.1",
|
|
107
107
|
"raw-loader": "^4.0.2",
|
|
108
|
-
"rimraf": "^
|
|
109
|
-
"rollup": "^4.19.
|
|
108
|
+
"rimraf": "^5.0.10",
|
|
109
|
+
"rollup": "^4.19.2",
|
|
110
110
|
"threads-plugin": "^1.4.0",
|
|
111
111
|
"tiny-worker": "^2.3.0",
|
|
112
112
|
"ts-loader": "^9.5.1",
|
package/register.d.ts
CHANGED
package/rollup.config.js
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable import/no-internal-modules */
|
|
1
2
|
// tslint:disable max-classes-per-file
|
|
2
3
|
|
|
3
4
|
import { ImplementationExport, ThreadsWorkerOptions } from '../types/master'
|
|
@@ -36,10 +37,10 @@ function selectWorkerImplementation(): ImplementationExport {
|
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
if (
|
|
39
|
-
typeof url === 'string'
|
|
40
|
-
isAbsoluteURL(url)
|
|
40
|
+
typeof url === 'string'
|
|
41
|
+
&& isAbsoluteURL(url) // Create source code blob loading JS file via `importScripts()`
|
|
41
42
|
// to circumvent worker CORS restrictions
|
|
42
|
-
(options?.CORSWorkaround ?? true)
|
|
43
|
+
&& (options?.CORSWorkaround ?? true)
|
|
43
44
|
) {
|
|
44
45
|
url = createSourceBlobURL(`importScripts(${JSON.stringify(url)});`)
|
|
45
46
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
2
|
+
/* eslint-disable import/no-internal-modules */
|
|
1
3
|
/* eslint-disable unicorn/no-process-exit */
|
|
2
|
-
/* eslint-disable sonarjs/no-identical-functions */
|
|
3
4
|
/* eslint-disable unicorn/prefer-logical-operator-over-ternary */
|
|
4
5
|
/* eslint-disable unicorn/prefer-regexp-test */
|
|
5
|
-
|
|
6
|
+
|
|
6
7
|
/* eslint-disable unicorn/prefer-add-event-listener */
|
|
7
8
|
/* eslint-disable unicorn/prefer-event-target */
|
|
8
9
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
@@ -85,15 +86,15 @@ function resolveScriptPath(scriptPath: string, baseURL?: string | undefined) {
|
|
|
85
86
|
return path.isAbsolute(filePath) ? filePath : path.join(baseURL || eval('__dirname'), filePath)
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
return typeof __non_webpack_require__ === 'function'
|
|
89
|
-
|
|
89
|
+
return typeof __non_webpack_require__ === 'function'
|
|
90
|
+
? __non_webpack_require__.resolve(makeRelative(scriptPath))
|
|
90
91
|
: eval('require').resolve(makeRelative(rebaseScriptPath(scriptPath, /[/\\]worker_threads[/\\]/)))
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
function initWorkerThreadsWorker(): ImplementationExport {
|
|
94
95
|
// Webpack hack
|
|
95
|
-
const NativeWorker
|
|
96
|
-
typeof __non_webpack_require__ === 'function' ? __non_webpack_require__('worker_threads').Worker : eval('require')('worker_threads').Worker
|
|
96
|
+
const NativeWorker
|
|
97
|
+
= typeof __non_webpack_require__ === 'function' ? __non_webpack_require__('worker_threads').Worker : eval('require')('worker_threads').Worker
|
|
97
98
|
|
|
98
99
|
let allWorkers: Array<typeof NativeWorker> = []
|
|
99
100
|
|
|
@@ -136,7 +137,7 @@ function initWorkerThreadsWorker(): ImplementationExport {
|
|
|
136
137
|
|
|
137
138
|
const terminateWorkersAndMaster = () => {
|
|
138
139
|
// we should terminate all workers and then gracefully shutdown self process
|
|
139
|
-
Promise.all(allWorkers.map(
|
|
140
|
+
Promise.all(allWorkers.map(worker => worker.terminate())).then(
|
|
140
141
|
() => process.exit(0),
|
|
141
142
|
() => process.exit(1),
|
|
142
143
|
)
|
|
@@ -174,10 +175,12 @@ function initTinyWorker(): ImplementationExport {
|
|
|
174
175
|
constructor(scriptPath: string, options?: ThreadsWorkerOptions & { fromSource?: boolean }) {
|
|
175
176
|
// Need to apply a work-around for Windows or it will choke upon the absolute path
|
|
176
177
|
// (`Error [ERR_INVALID_PROTOCOL]: Protocol 'c:' not supported`)
|
|
177
|
-
const resolvedScriptPath
|
|
178
|
-
options && options.fromSource
|
|
179
|
-
|
|
180
|
-
|
|
178
|
+
const resolvedScriptPath
|
|
179
|
+
= options && options.fromSource
|
|
180
|
+
? null
|
|
181
|
+
: process.platform === 'win32'
|
|
182
|
+
? `file:///${resolveScriptPath(scriptPath).replaceAll('\\', '/')}`
|
|
183
|
+
: resolveScriptPath(scriptPath)
|
|
181
184
|
|
|
182
185
|
if (!resolvedScriptPath) {
|
|
183
186
|
// `options.fromSource` is true
|
|
@@ -208,14 +211,14 @@ function initTinyWorker(): ImplementationExport {
|
|
|
208
211
|
}
|
|
209
212
|
|
|
210
213
|
terminate() {
|
|
211
|
-
allWorkers = allWorkers.filter(
|
|
214
|
+
allWorkers = allWorkers.filter(worker => worker !== this)
|
|
212
215
|
return super.terminate()
|
|
213
216
|
}
|
|
214
217
|
}
|
|
215
218
|
|
|
216
219
|
const terminateWorkersAndMaster = () => {
|
|
217
220
|
// we should terminate all workers and then gracefully shutdown self process
|
|
218
|
-
Promise.all(allWorkers.map(
|
|
221
|
+
Promise.all(allWorkers.map(worker => worker.terminate())).then(
|
|
219
222
|
() => process.exit(0),
|
|
220
223
|
() => process.exit(1),
|
|
221
224
|
)
|
|
@@ -270,10 +273,10 @@ export function isWorkerRuntime() {
|
|
|
270
273
|
return self !== undefined && self['postMessage'] ? true : false
|
|
271
274
|
} else {
|
|
272
275
|
// Webpack hack
|
|
273
|
-
const isMainThread
|
|
274
|
-
typeof __non_webpack_require__ === 'function'
|
|
275
|
-
__non_webpack_require__('worker_threads').isMainThread
|
|
276
|
-
|
|
276
|
+
const isMainThread
|
|
277
|
+
= typeof __non_webpack_require__ === 'function'
|
|
278
|
+
? __non_webpack_require__('worker_threads').isMainThread
|
|
279
|
+
: eval('require')('worker_threads').isMainThread
|
|
277
280
|
return !isMainThread
|
|
278
281
|
}
|
|
279
282
|
}
|
package/src/master/index.ts
CHANGED