Skip to content

Commit adb07c1

Browse files
authored
Let the user choose worker implementation (#64)
undefined
1 parent 14bcdb1 commit adb07c1

File tree

64 files changed

+1279
-3595
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1279
-3595
lines changed

Readme.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ Describes a WorkerNodes options.
105105
* [.workerEndurance](#WorkerNodesOptions+workerEndurance) : <code>Number</code>
106106
* [.workerStopTimeout](#WorkerNodesOptions+workerStopTimeout) : <code>Number</code>
107107
* [.resourceLimits](#WorkerNodesOptions+resourceLimits) : <code>Object</code>
108+
* [.workerType](#WorkerNodesOptions+workerType) : <code>string</code>
108109

109110
<a name="WorkerNodesOptions+autoStart"></a>
110111

@@ -195,7 +196,7 @@ The timeout value (in milliseconds) for the worker to stop before sending SIGKIL
195196
<a name="WorkerNodesOptions+resourceLimits"></a>
196197

197198
### options.resourceLimits : <code>Object</code>
198-
Provides the set of JS engine resource constraints inside this Worker thread.
199+
Provides the set of JS engine resource constraints inside this Worker thread. (Usable when using `workerType: thread` only)
199200

200201
**Kind**: instance property of [<code>WorkerNodesOptions</code>](#WorkerNodesOptions)
201202
**Properties**
@@ -207,6 +208,10 @@ Provides the set of JS engine resource constraints inside this Worker thread.
207208
| codeRangeSizeMb | <code>Number</code> | The size of a pre-allocated memory range used for generated code |
208209
| stackSizeMb | <code>Number</code> | The default maximum stack size for the thread. Small values may lead to unusable Worker instances |
209210

211+
### options.workerType : <code>string</code>
212+
Can be either `process` or `thread` (default), that controls the underlying implementation used, either `child_process` or `worker_threads`.
213+
Most usecases are perfectly fine with `thread` implementation, some work loads though, might need to use `process`, for example, if you are using
214+
`process.chdir()` call which is [not supported](https://github.com/nodejs/node/issues/41673) in `worker_threads`.
210215

211216
## Example
212217

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const testBase = require("./async-initialization.base");
2+
3+
testBase("process");
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const testBase = require("./async-initialization.base");
2+
3+
testBase("thread");

e2e/async-initialization.base.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const test = require('ava');
2+
3+
const WorkerNodes = require('../');
4+
const { fixture } = require('./utils');
5+
6+
module.exports = function describe(workerType) {
7+
test(`should not mark worker as ready until module fully initialized`, t => {
8+
// given
9+
const workerNodes = new WorkerNodes(fixture('async-initialization'), {
10+
maxWorkers: 1,
11+
asyncWorkerInitialization: true,
12+
autoStart: true,
13+
workerType
14+
});
15+
16+
// then
17+
t.falsy(workerNodes.pickWorker());
18+
});
19+
20+
test(`should correctly handle task after initialization`, async t => {
21+
// given
22+
const workerNodes = new WorkerNodes(fixture('async-initialization'), {
23+
maxWorkers: 1,
24+
asyncWorkerInitialization: true,
25+
autoStart: true,
26+
workerType
27+
});
28+
29+
// when
30+
const result = await workerNodes.call.result();
31+
32+
// then
33+
t.is(result, 'result');
34+
});
35+
}

e2e/async-initialization.spec.js

Lines changed: 0 additions & 31 deletions
This file was deleted.

e2e/auto-start-process.spec.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const testBase = require("./auto-start.base");
2+
3+
testBase("process");

e2e/auto-start-thread.spec.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const testBase = require("./auto-start.base");
2+
3+
testBase("thread");

e2e/auto-start.base.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
const test = require('ava');
2+
3+
const WorkerNodes = require('../');
4+
const { fixture, unique, repeatCall, eventually } = require('./utils');
5+
6+
module.exports = function describe(workerType) {
7+
test(`should be disabled by default`, async t => {
8+
// given
9+
const workerNodes = new WorkerNodes(fixture('process-info'), { workerType });
10+
11+
// when
12+
const callTime = new Date();
13+
await workerNodes.call.noop();
14+
15+
// then
16+
workerNodes.workersQueue.forEach(worker => {
17+
const startDate = worker.process.startDate;
18+
19+
if (startDate) {
20+
t.true(startDate >= callTime);
21+
}
22+
});
23+
});
24+
25+
test(`should result in spawn of the workers before the first call if active`, async t => {
26+
// given
27+
const workerNodes = new WorkerNodes(fixture('process-info'), { autoStart: true, minWorkers: 1, maxWorkers: 1, workerType });
28+
await workerNodes.ready();
29+
30+
// when
31+
const callTime = Date.now();
32+
const workerStartTime = await workerNodes.call.getStartTime();
33+
34+
// then
35+
t.true(workerStartTime <= callTime);
36+
});
37+
38+
test(`should force the workerNodes to wait for all the required workers to start before reporting ready`, async t => {
39+
// given
40+
const workerNodes = new WorkerNodes(fixture('process-info'), { autoStart: true, minWorkers: 4, maxWorkers: 4, workerType });
41+
await workerNodes.ready();
42+
const callStartTime = Date.now();
43+
44+
// when
45+
const results = await repeatCall(workerNodes.call.getStartTime, 4);
46+
47+
// then
48+
t.is(results.length, 4);
49+
50+
results.forEach(result => t.true(result <= callStartTime));
51+
});
52+
53+
test(`should only use workers that are fully initialized`, async t => {
54+
// given
55+
const workerNodes = new WorkerNodes(fixture('slow-module'), {
56+
autoStart: true,
57+
minWorkers: 2,
58+
maxWorkers: 2,
59+
taskMaxRetries: Infinity,
60+
workerType
61+
});
62+
await workerNodes.ready();
63+
64+
await repeatCall(workerNodes.call.getPid, 4);
65+
66+
// when
67+
workerNodes.workersQueue.storage[0].process.exit();
68+
await repeatCall(workerNodes.call.getPid, 4);
69+
70+
// then
71+
// we wait for all workers to come back a live
72+
const getLiveWorkers = () => workerNodes.workersQueue.filter(worker => worker.isProcessAlive);
73+
await eventually(() => unique(getLiveWorkers()).length === 2);
74+
t.is(unique(getLiveWorkers()).length, 2);
75+
});
76+
}

e2e/auto-start.spec.js

Lines changed: 0 additions & 71 deletions
This file was deleted.

e2e/call-timeout-process.spec.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const testBase = require("./call-timeout.base");
2+
3+
testBase("process");

0 commit comments

Comments
 (0)