threadsx 2.0.2 → 2.2.0
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/errors.d.ts +16 -0
- package/dist/errors.js +31 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/master/implementation.node.js +34 -18
- package/dist/master/invocation-proxy.js +45 -11
- package/dist/master/pool.d.ts +1 -24
- package/dist/master/pool.js +41 -8
- package/dist/master/spawn.js +24 -7
- package/dist/node-require.d.ts +13 -0
- package/dist/node-require.js +87 -0
- package/dist/transferable.d.ts +1 -0
- package/dist/types/master.d.ts +22 -1
- package/dist/types/master.js +0 -1
- package/dist/types/worker.d.ts +1 -0
- package/dist/worker/implementation.browser.d.ts +1 -1
- package/dist/worker/implementation.worker_threads.d.ts +1 -1
- package/dist/worker_threads.d.ts +3 -7
- package/dist/worker_threads.js +35 -11
- package/dist-esm/common.js +1 -0
- package/dist-esm/common.js.map +1 -0
- package/dist-esm/errors.js +27 -0
- package/dist-esm/errors.js.map +1 -0
- package/dist-esm/index.js +2 -0
- package/dist-esm/index.js.map +1 -0
- package/dist-esm/master/get-bundle-url.browser.js +1 -0
- package/dist-esm/master/get-bundle-url.browser.js.map +1 -0
- package/dist-esm/master/implementation.browser.js +1 -0
- package/dist-esm/master/implementation.browser.js.map +1 -0
- package/dist-esm/master/implementation.js +1 -0
- package/dist-esm/master/implementation.js.map +1 -0
- package/dist-esm/master/implementation.node.js +35 -18
- package/dist-esm/master/implementation.node.js.map +1 -0
- package/dist-esm/master/index.js +1 -0
- package/dist-esm/master/index.js.map +1 -0
- package/dist-esm/master/invocation-proxy.js +46 -11
- package/dist-esm/master/invocation-proxy.js.map +1 -0
- package/dist-esm/master/pool-types.js +1 -0
- package/dist-esm/master/pool-types.js.map +1 -0
- package/dist-esm/master/pool.js +42 -8
- package/dist-esm/master/pool.js.map +1 -0
- package/dist-esm/master/register.js +1 -0
- package/dist-esm/master/register.js.map +1 -0
- package/dist-esm/master/spawn.js +25 -7
- package/dist-esm/master/spawn.js.map +1 -0
- package/dist-esm/master/thread.js +1 -0
- package/dist-esm/master/thread.js.map +1 -0
- package/dist-esm/node-require.js +50 -0
- package/dist-esm/node-require.js.map +1 -0
- package/dist-esm/observable-promise.js +1 -0
- package/dist-esm/observable-promise.js.map +1 -0
- package/dist-esm/observable.js +1 -0
- package/dist-esm/observable.js.map +1 -0
- package/dist-esm/ponyfills.js +1 -0
- package/dist-esm/ponyfills.js.map +1 -0
- package/dist-esm/promise.js +1 -0
- package/dist-esm/promise.js.map +1 -0
- package/dist-esm/serializers.js +1 -0
- package/dist-esm/serializers.js.map +1 -0
- package/dist-esm/symbols.js +1 -0
- package/dist-esm/symbols.js.map +1 -0
- package/dist-esm/transferable.js +1 -0
- package/dist-esm/transferable.js.map +1 -0
- package/dist-esm/types/master.js +1 -1
- package/dist-esm/types/master.js.map +1 -0
- package/dist-esm/types/messages.js +1 -0
- package/dist-esm/types/messages.js.map +1 -0
- package/dist-esm/types/worker.js +1 -0
- package/dist-esm/types/worker.js.map +1 -0
- package/dist-esm/worker/bundle-entry.js +1 -0
- package/dist-esm/worker/bundle-entry.js.map +1 -0
- package/dist-esm/worker/implementation.browser.js +1 -0
- package/dist-esm/worker/implementation.browser.js.map +1 -0
- package/dist-esm/worker/implementation.js +1 -0
- package/dist-esm/worker/implementation.js.map +1 -0
- package/dist-esm/worker/implementation.worker_threads.js +1 -0
- package/dist-esm/worker/implementation.worker_threads.js.map +1 -0
- package/dist-esm/worker/index.js +1 -0
- package/dist-esm/worker/index.js.map +1 -0
- package/dist-esm/worker_threads.js +3 -11
- package/dist-esm/worker_threads.js.map +1 -0
- package/esm/common.mjs +20 -0
- package/esm/errors.mjs +34 -0
- package/esm/index.mjs +16 -0
- package/esm/master/get-bundle-url.browser.mjs +32 -0
- package/esm/master/implementation.browser.mjs +76 -0
- package/esm/master/implementation.mjs +24 -0
- package/esm/master/implementation.node.mjs +186 -0
- package/esm/master/index.mjs +17 -0
- package/esm/master/invocation-proxy.mjs +164 -0
- package/esm/master/pool-types.mjs +20 -0
- package/esm/master/pool.mjs +324 -0
- package/esm/master/register.mjs +14 -0
- package/esm/master/spawn.mjs +179 -0
- package/esm/master/thread.mjs +28 -0
- package/esm/node-require.mjs +58 -0
- package/esm/observable-promise.mjs +155 -0
- package/esm/observable.mjs +45 -0
- package/esm/ponyfills.mjs +26 -0
- package/esm/promise.mjs +32 -0
- package/esm/serializers.mjs +55 -0
- package/esm/symbols.mjs +13 -0
- package/esm/transferable.mjs +31 -0
- package/esm/types/master.mjs +15 -0
- package/esm/types/messages.mjs +25 -0
- package/esm/worker/implementation.browser.mjs +31 -0
- package/esm/worker/implementation.mjs +21 -0
- package/esm/worker/implementation.worker_threads.mjs +44 -0
- package/esm/worker/index.mjs +224 -0
- package/esm/worker_threads.mjs +13 -0
- package/package.json +32 -24
- package/index.mjs +0 -4
- package/observable.mjs +0 -1
- package/register.mjs +0 -2
- package/worker.mjs +0 -1
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "module";
|
|
2
|
+
import { fileURLToPath as __fileURLToPath } from "url";
|
|
3
|
+
import { dirname as __pathDirname } from "path";
|
|
4
|
+
const require = __createRequire(import.meta.url);
|
|
5
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = __pathDirname(__filename);
|
|
7
|
+
import getCallsites from 'callsites';
|
|
8
|
+
import { cpus } from 'os';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
import { isWebpackBundle, getNodeRequire, getModuleDirname } from '../node-require.mjs';
|
|
12
|
+
import getImplementation from '../worker_threads.mjs';
|
|
13
|
+
|
|
14
|
+
/// <reference lib="dom" />
|
|
15
|
+
// NOTE: `callsites` is intentionally pinned to ^3. v4+ is ESM-only and would
|
|
16
|
+
// break the CommonJS (dist/) build. Do not bump it to v4 without moving the
|
|
17
|
+
// package to ESM-first output. (See .github/dependabot.yml, which also ignores
|
|
18
|
+
// its major updates.)
|
|
19
|
+
let detectedTsRuntime;
|
|
20
|
+
const defaultPoolSize = cpus().length;
|
|
21
|
+
/**
|
|
22
|
+
* Whether the application opted out of threadsx installing SIGINT/SIGTERM
|
|
23
|
+
* handlers (which call `process.exit()`), via `THREADS_SKIP_SIGNAL_HANDLERS`.
|
|
24
|
+
*/
|
|
25
|
+
function signalHandlersDisabled() {
|
|
26
|
+
const value = typeof process !== "undefined" && process.env
|
|
27
|
+
? process.env.THREADS_SKIP_SIGNAL_HANDLERS
|
|
28
|
+
: undefined;
|
|
29
|
+
return value === "1" || value === "true";
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Detects an available TypeScript runtime so `.ts`/`.tsx` worker files can be
|
|
33
|
+
* spawned directly during development. Prefers `tsx`, falls back to `ts-node`.
|
|
34
|
+
*/
|
|
35
|
+
function detectTsRuntime() {
|
|
36
|
+
if (isWebpackBundle()) {
|
|
37
|
+
// Webpack build: => No TS runtime required or possible
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
if (detectedTsRuntime !== undefined) {
|
|
41
|
+
return detectedTsRuntime;
|
|
42
|
+
}
|
|
43
|
+
detectedTsRuntime = null;
|
|
44
|
+
for (const candidate of ["tsx", "ts-node"]) {
|
|
45
|
+
try {
|
|
46
|
+
getNodeRequire().resolve(candidate);
|
|
47
|
+
detectedTsRuntime = candidate;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (error && error.code === "MODULE_NOT_FOUND") {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
// Re-throw
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return detectedTsRuntime;
|
|
59
|
+
}
|
|
60
|
+
function createTsRuntimeModule(scriptPath, runtime) {
|
|
61
|
+
const register = runtime === "tsx"
|
|
62
|
+
? `require("tsx/cjs");`
|
|
63
|
+
: `require("ts-node/register/transpile-only");`;
|
|
64
|
+
const content = `
|
|
65
|
+
${register}
|
|
66
|
+
require(${JSON.stringify(scriptPath)});
|
|
67
|
+
`;
|
|
68
|
+
return content;
|
|
69
|
+
}
|
|
70
|
+
function rebaseScriptPath(scriptPath, ignoreRegex) {
|
|
71
|
+
// An already-absolute path (e.g. from `new Worker(new URL("./w", import.meta.url))`,
|
|
72
|
+
// which threadsx normalizes to a filesystem path) must not be rebased onto the
|
|
73
|
+
// caller's directory — doing so would prepend it and corrupt the path.
|
|
74
|
+
if (path.isAbsolute(scriptPath)) {
|
|
75
|
+
return scriptPath;
|
|
76
|
+
}
|
|
77
|
+
const parentCallSite = getCallsites().find((callsite) => {
|
|
78
|
+
const filename = callsite.getFileName();
|
|
79
|
+
return Boolean(filename &&
|
|
80
|
+
!filename.match(ignoreRegex) &&
|
|
81
|
+
!filename.match(/[/\\]master[/\\]implementation/) &&
|
|
82
|
+
!filename.match(/^internal\/process/));
|
|
83
|
+
});
|
|
84
|
+
const rawCallerPath = parentCallSite ? parentCallSite.getFileName() : null;
|
|
85
|
+
let callerPath = rawCallerPath ? rawCallerPath : null;
|
|
86
|
+
if (callerPath && callerPath.startsWith('file:')) {
|
|
87
|
+
callerPath = fileURLToPath(callerPath);
|
|
88
|
+
}
|
|
89
|
+
const rebasedScriptPath = callerPath ? path.join(path.dirname(callerPath), scriptPath) : scriptPath;
|
|
90
|
+
return rebasedScriptPath;
|
|
91
|
+
}
|
|
92
|
+
function resolveScriptPath(scriptPath, baseURL) {
|
|
93
|
+
const makeRelative = (filePath) => {
|
|
94
|
+
return path.isAbsolute(filePath) ? filePath : path.join(baseURL || getModuleDirname(), filePath);
|
|
95
|
+
};
|
|
96
|
+
// In a webpack bundle, walking the call stack is useless (every caller lives
|
|
97
|
+
// inside the bundle), so relative paths resolve without rebasing.
|
|
98
|
+
const workerFilePath = isWebpackBundle()
|
|
99
|
+
? getNodeRequire().resolve(makeRelative(scriptPath))
|
|
100
|
+
: getNodeRequire().resolve(makeRelative(rebaseScriptPath(scriptPath, /[/\\]worker_threads[/\\]/)));
|
|
101
|
+
return workerFilePath;
|
|
102
|
+
}
|
|
103
|
+
function initWorkerThreadsWorker() {
|
|
104
|
+
const NativeWorker = getImplementation().Worker;
|
|
105
|
+
let allWorkers = [];
|
|
106
|
+
class Worker extends NativeWorker {
|
|
107
|
+
constructor(scriptPath, options) {
|
|
108
|
+
// Bundlers like webpack 5 pass a `URL` (from `new Worker(new URL(...))`)
|
|
109
|
+
// pointing at the emitted worker chunk.
|
|
110
|
+
const normalizedScriptPath = scriptPath instanceof URL ? fileURLToPath(scriptPath) : scriptPath;
|
|
111
|
+
const resolvedScriptPath = options && options.fromSource
|
|
112
|
+
? null
|
|
113
|
+
: resolveScriptPath(normalizedScriptPath, (options || {})._baseURL);
|
|
114
|
+
const tsRuntime = resolvedScriptPath && /\.tsx?$/i.test(resolvedScriptPath) ? detectTsRuntime() : null;
|
|
115
|
+
if (!resolvedScriptPath) {
|
|
116
|
+
// `options.fromSource` is true
|
|
117
|
+
const sourceCode = scriptPath;
|
|
118
|
+
super(sourceCode, Object.assign(Object.assign({}, options), { eval: true }));
|
|
119
|
+
}
|
|
120
|
+
else if (tsRuntime) {
|
|
121
|
+
super(createTsRuntimeModule(resolvedScriptPath, tsRuntime), Object.assign(Object.assign({}, options), { eval: true }));
|
|
122
|
+
}
|
|
123
|
+
else if (resolvedScriptPath.match(/\.asar[/\\]/)) {
|
|
124
|
+
// See <https://github.com/andywer/threads-plugin/issues/17>
|
|
125
|
+
super(resolvedScriptPath.replace(/\.asar([/\\])/, ".asar.unpacked$1"), options);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
super(resolvedScriptPath, options);
|
|
129
|
+
}
|
|
130
|
+
this.mappedEventListeners = new WeakMap();
|
|
131
|
+
allWorkers.push(this);
|
|
132
|
+
}
|
|
133
|
+
addEventListener(eventName, rawListener) {
|
|
134
|
+
const listener = (message) => {
|
|
135
|
+
rawListener({ data: message });
|
|
136
|
+
};
|
|
137
|
+
this.mappedEventListeners.set(rawListener, listener);
|
|
138
|
+
this.on(eventName, listener);
|
|
139
|
+
}
|
|
140
|
+
removeEventListener(eventName, rawListener) {
|
|
141
|
+
const listener = this.mappedEventListeners.get(rawListener) || rawListener;
|
|
142
|
+
this.off(eventName, listener);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const terminateWorkersAndMaster = () => {
|
|
146
|
+
// we should terminate all workers and then gracefully shutdown self process
|
|
147
|
+
Promise.all(allWorkers.map(worker => worker.terminate())).then(() => process.exit(0), () => process.exit(1));
|
|
148
|
+
allWorkers = [];
|
|
149
|
+
};
|
|
150
|
+
// Take care to not leave orphaned processes behind. See #147.
|
|
151
|
+
//
|
|
152
|
+
// These handlers call process.exit(), which hijacks the host application's
|
|
153
|
+
// own shutdown. Applications that manage their own graceful shutdown can opt
|
|
154
|
+
// out by setting THREADS_SKIP_SIGNAL_HANDLERS. See upstream #388 / #484.
|
|
155
|
+
if (!signalHandlersDisabled()) {
|
|
156
|
+
process.on("SIGINT", () => terminateWorkersAndMaster());
|
|
157
|
+
process.on("SIGTERM", () => terminateWorkersAndMaster());
|
|
158
|
+
}
|
|
159
|
+
class BlobWorker extends Worker {
|
|
160
|
+
constructor(blob, options) {
|
|
161
|
+
super(Buffer.from(blob).toString("utf-8"), Object.assign(Object.assign({}, options), { fromSource: true }));
|
|
162
|
+
}
|
|
163
|
+
static fromText(source, options) {
|
|
164
|
+
return new Worker(source, Object.assign(Object.assign({}, options), { fromSource: true }));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
blob: BlobWorker,
|
|
169
|
+
default: Worker
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
let implementation;
|
|
173
|
+
function selectWorkerImplementation() {
|
|
174
|
+
return initWorkerThreadsWorker();
|
|
175
|
+
}
|
|
176
|
+
function getWorkerImplementation() {
|
|
177
|
+
if (!implementation) {
|
|
178
|
+
implementation = selectWorkerImplementation();
|
|
179
|
+
}
|
|
180
|
+
return implementation;
|
|
181
|
+
}
|
|
182
|
+
function isWorkerRuntime() {
|
|
183
|
+
return !getImplementation().isMainThread;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export { defaultPoolSize, getWorkerImplementation, isWorkerRuntime };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "module";
|
|
2
|
+
import { fileURLToPath as __fileURLToPath } from "url";
|
|
3
|
+
import { dirname as __pathDirname } from "path";
|
|
4
|
+
const require = __createRequire(import.meta.url);
|
|
5
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = __pathDirname(__filename);
|
|
7
|
+
import { getWorkerImplementation } from './implementation.mjs';
|
|
8
|
+
export { isWorkerRuntime } from './implementation.mjs';
|
|
9
|
+
export { Pool } from './pool.mjs';
|
|
10
|
+
export { spawn } from './spawn.mjs';
|
|
11
|
+
|
|
12
|
+
/** Separate class to spawn workers from source code blobs or strings. */
|
|
13
|
+
const BlobWorker = getWorkerImplementation().blob;
|
|
14
|
+
/** Worker implementation. Either web worker or a node.js Worker class. */
|
|
15
|
+
const Worker = getWorkerImplementation().default;
|
|
16
|
+
|
|
17
|
+
export { BlobWorker, Worker };
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "module";
|
|
2
|
+
import { fileURLToPath as __fileURLToPath } from "url";
|
|
3
|
+
import { dirname as __pathDirname } from "path";
|
|
4
|
+
const require = __createRequire(import.meta.url);
|
|
5
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = __pathDirname(__filename);
|
|
7
|
+
import DebugLogger from 'debug';
|
|
8
|
+
import { multicast, Observable } from 'observable-fns';
|
|
9
|
+
import { serialize, deserialize } from '../common.mjs';
|
|
10
|
+
import { isDataCloneError, ThreadCloneError } from '../errors.mjs';
|
|
11
|
+
import { ObservablePromise } from '../observable-promise.mjs';
|
|
12
|
+
import { isTransferDescriptor } from '../transferable.mjs';
|
|
13
|
+
import { MasterMessageType, WorkerMessageType } from '../types/messages.mjs';
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* This source file contains the code for proxying calls in the master thread to calls in the workers
|
|
17
|
+
* by `.postMessage()`-ing.
|
|
18
|
+
*
|
|
19
|
+
* Keep in mind that this code can make or break the program's performance! Need to optimize more…
|
|
20
|
+
*/
|
|
21
|
+
const debugMessages = DebugLogger("threads:master:messages");
|
|
22
|
+
let nextJobUID = 1;
|
|
23
|
+
const dedupe = (array) => Array.from(new Set(array));
|
|
24
|
+
const isJobErrorMessage = (data) => data && data.type === WorkerMessageType.error;
|
|
25
|
+
const isJobResultMessage = (data) => data && data.type === WorkerMessageType.result;
|
|
26
|
+
const isJobStartMessage = (data) => data && data.type === WorkerMessageType.running;
|
|
27
|
+
function createObservableForJob(worker, jobUID) {
|
|
28
|
+
return new Observable(observer => {
|
|
29
|
+
let asyncType;
|
|
30
|
+
let settled = false;
|
|
31
|
+
const cleanup = () => {
|
|
32
|
+
worker.removeEventListener("message", messageHandler);
|
|
33
|
+
worker.removeEventListener("error", errorHandler);
|
|
34
|
+
worker.removeEventListener("exit", exitHandler);
|
|
35
|
+
};
|
|
36
|
+
const messageHandler = ((event) => {
|
|
37
|
+
debugMessages("Message from worker:", event.data);
|
|
38
|
+
if (!event.data || event.data.uid !== jobUID)
|
|
39
|
+
return;
|
|
40
|
+
if (isJobStartMessage(event.data)) {
|
|
41
|
+
asyncType = event.data.resultType;
|
|
42
|
+
}
|
|
43
|
+
else if (isJobResultMessage(event.data)) {
|
|
44
|
+
if (asyncType === "promise") {
|
|
45
|
+
if (typeof event.data.payload !== "undefined") {
|
|
46
|
+
observer.next(deserialize(event.data.payload));
|
|
47
|
+
}
|
|
48
|
+
settled = true;
|
|
49
|
+
observer.complete();
|
|
50
|
+
cleanup();
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
if (typeof event.data.payload !== "undefined") {
|
|
54
|
+
observer.next(deserialize(event.data.payload));
|
|
55
|
+
}
|
|
56
|
+
if (event.data.complete) {
|
|
57
|
+
settled = true;
|
|
58
|
+
observer.complete();
|
|
59
|
+
cleanup();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else if (isJobErrorMessage(event.data)) {
|
|
64
|
+
const error = deserialize(event.data.error);
|
|
65
|
+
settled = true;
|
|
66
|
+
observer.error(error);
|
|
67
|
+
cleanup();
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
// If the worker crashes or is terminated before the job produces a result,
|
|
71
|
+
// reject the pending job instead of leaving the promise hanging forever.
|
|
72
|
+
// See #386.
|
|
73
|
+
const errorHandler = ((event) => {
|
|
74
|
+
if (settled)
|
|
75
|
+
return;
|
|
76
|
+
settled = true;
|
|
77
|
+
const error = event && event.data instanceof Error
|
|
78
|
+
? event.data
|
|
79
|
+
: Error(String((event && event.data) || "Worker errored before the job completed."));
|
|
80
|
+
observer.error(error);
|
|
81
|
+
cleanup();
|
|
82
|
+
});
|
|
83
|
+
const exitHandler = ((event) => {
|
|
84
|
+
if (settled)
|
|
85
|
+
return;
|
|
86
|
+
settled = true;
|
|
87
|
+
const exitCode = event ? event.data : undefined;
|
|
88
|
+
observer.error(Error(`Worker terminated before the job completed (exit code: ${exitCode}).`));
|
|
89
|
+
cleanup();
|
|
90
|
+
});
|
|
91
|
+
worker.addEventListener("message", messageHandler);
|
|
92
|
+
worker.addEventListener("error", errorHandler);
|
|
93
|
+
worker.addEventListener("exit", exitHandler);
|
|
94
|
+
return () => {
|
|
95
|
+
if (asyncType === "observable" || !asyncType) {
|
|
96
|
+
const cancelMessage = {
|
|
97
|
+
type: MasterMessageType.cancel,
|
|
98
|
+
uid: jobUID
|
|
99
|
+
};
|
|
100
|
+
worker.postMessage(cancelMessage);
|
|
101
|
+
}
|
|
102
|
+
cleanup();
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function prepareArguments(rawArgs) {
|
|
107
|
+
if (rawArgs.length === 0) {
|
|
108
|
+
// Exit early if possible
|
|
109
|
+
return {
|
|
110
|
+
args: [],
|
|
111
|
+
transferables: []
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const args = [];
|
|
115
|
+
const transferables = [];
|
|
116
|
+
for (const arg of rawArgs) {
|
|
117
|
+
if (isTransferDescriptor(arg)) {
|
|
118
|
+
args.push(serialize(arg.send));
|
|
119
|
+
transferables.push(...arg.transferables);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
args.push(serialize(arg));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
args,
|
|
127
|
+
transferables: transferables.length === 0 ? transferables : dedupe(transferables)
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function createProxyFunction(worker, method) {
|
|
131
|
+
return ((...rawArgs) => {
|
|
132
|
+
const uid = nextJobUID++;
|
|
133
|
+
const { args, transferables } = prepareArguments(rawArgs);
|
|
134
|
+
const runMessage = {
|
|
135
|
+
type: MasterMessageType.run,
|
|
136
|
+
uid,
|
|
137
|
+
method,
|
|
138
|
+
args
|
|
139
|
+
};
|
|
140
|
+
debugMessages("Sending command to run function to worker:", runMessage);
|
|
141
|
+
try {
|
|
142
|
+
worker.postMessage(runMessage, transferables);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
if (isDataCloneError(error)) {
|
|
146
|
+
const cloneError = new ThreadCloneError(`Cannot send arguments to the worker thread: a value is not structured-cloneable. ` +
|
|
147
|
+
`Functions, class instances and other non-serializable values cannot be passed to a thread. ` +
|
|
148
|
+
`Original error: ${error.message}`, error);
|
|
149
|
+
return ObservablePromise.from(Promise.reject(cloneError));
|
|
150
|
+
}
|
|
151
|
+
return ObservablePromise.from(Promise.reject(error));
|
|
152
|
+
}
|
|
153
|
+
return ObservablePromise.from(multicast(createObservableForJob(worker, uid)));
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function createProxyModule(worker, methodNames) {
|
|
157
|
+
const proxy = {};
|
|
158
|
+
for (const methodName of methodNames) {
|
|
159
|
+
proxy[methodName] = createProxyFunction(worker, methodName);
|
|
160
|
+
}
|
|
161
|
+
return proxy;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export { createProxyFunction, createProxyModule };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "module";
|
|
2
|
+
import { fileURLToPath as __fileURLToPath } from "url";
|
|
3
|
+
import { dirname as __pathDirname } from "path";
|
|
4
|
+
const require = __createRequire(import.meta.url);
|
|
5
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = __pathDirname(__filename);
|
|
7
|
+
/** Pool event type. Specifies the type of each `PoolEvent`. */
|
|
8
|
+
var PoolEventType;
|
|
9
|
+
(function (PoolEventType) {
|
|
10
|
+
PoolEventType["initialized"] = "initialized";
|
|
11
|
+
PoolEventType["taskCanceled"] = "taskCanceled";
|
|
12
|
+
PoolEventType["taskCompleted"] = "taskCompleted";
|
|
13
|
+
PoolEventType["taskFailed"] = "taskFailed";
|
|
14
|
+
PoolEventType["taskQueued"] = "taskQueued";
|
|
15
|
+
PoolEventType["taskQueueDrained"] = "taskQueueDrained";
|
|
16
|
+
PoolEventType["taskStart"] = "taskStart";
|
|
17
|
+
PoolEventType["terminated"] = "terminated";
|
|
18
|
+
})(PoolEventType || (PoolEventType = {}));
|
|
19
|
+
|
|
20
|
+
export { PoolEventType };
|