Skip to content

Commit f0f4fd3

Browse files
authored
feat: Allow long-running threads (piscinajs#757)
1 parent 9d23654 commit f0f4fd3

File tree

4 files changed

+50
-2
lines changed

4 files changed

+50
-2
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,9 @@ This class extends [`EventEmitter`][] from Node.js.
347347
running for this thread pool. The default is the number provided by [`os.availableParallelism`](https://nodejs.org/api/os.html#osavailableparallelism) * 1.5.
348348
* `idleTimeout`: (`number`) A timeout in milliseconds that specifies how long
349349
a `Worker` is allowed to be idle, i.e. not handling any tasks, before it is
350-
shut down. By default, this is immediate. **Tip**: *The default `idleTimeout`
350+
shut down. By default, this is immediate. If `Infinity` is passed as the value,
351+
the `Worker` never shuts down. Be careful when using `Infinity`,
352+
as it can lead to resource overuse. **Tip**: *The default `idleTimeout`
351353
can lead to some performance loss in the application because of the overhead
352354
involved with stopping and starting new worker threads. To improve performance,
353355
try setting the `idleTimeout` explicitly.*

docs/docs/api-reference/class.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,14 @@ This class extends [`EventEmitter`](https://nodejs.org/api/events.html) from Nod
3232
running for this thread pool. The default is the number provided by [`os.availableParallelism`](https://nodejs.org/api/os.html#osavailableparallelism) \* 1.5.
3333
- `idleTimeout`: (`number`) A timeout in milliseconds that specifies how long
3434
a `Worker` is allowed to be idle, i.e. not handling any tasks, before it is
35-
shut down. By default, this is immediate.
35+
shut down. By default, this is immediate. If `Infinity` is passed as the value,
36+
the `Worker` never shuts down.
3637
:::info
3738
The default `idleTimeout` can lead to some performance loss in the application because of the overhead involved with stopping and starting new worker threads. To improve performance, try setting the `idleTimeout` explicitly.
3839
:::
40+
:::info
41+
Be careful when when setting `idleTimeout` to `Infinity`, as this will prevent the worker from shutting down, even when idle, potentially leading to resource overuse.
42+
:::
3943
- `maxQueue`: (`number` | `string`) The maximum number of tasks that may be
4044
scheduled to run, but not yet running due to lack of available threads, at
4145
a given time. By default, there is no limit. The special value `'auto'`

src/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,11 @@ class ThreadPool {
435435
}
436436
}
437437

438+
//If Infinity was sent as a parameter, we skip setting the Timeout that clears the worker
439+
if (this.options.idleTimeout === Infinity) {
440+
return;
441+
}
442+
438443
// If more workers than minThreads, we can remove idle workers
439444
if (workerInfo.currentUsage() === 0 &&
440445
this.workers.size > this.options.minThreads) {

test/idle-timeout.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,40 @@ test('idle timeout will let go of threads early', async ({ equal }) => {
4242
equal(lateThreadIds.length, 2);
4343
equal(new Set([...earlyThreadIds, ...lateThreadIds]).size, 3);
4444
});
45+
46+
test('idle timeout will not let go of threads if Infinity is used as the value', async ({ deepEqual, equal }) => {
47+
const pool = new Piscina({
48+
filename: resolve(__dirname, 'fixtures/wait-for-others.ts'),
49+
idleTimeout: Infinity,
50+
minThreads: 1,
51+
maxThreads: 2
52+
});
53+
equal(pool.threads.length, 1);
54+
const buffer = new Int32Array(new SharedArrayBuffer(4));
55+
56+
const firstTasks = [
57+
pool.run([buffer, 2]),
58+
pool.run([buffer, 2])
59+
];
60+
equal(pool.threads.length, 2);
61+
62+
const earlyThreadIds = await Promise.all(firstTasks);
63+
equal(pool.threads.length, 2);
64+
65+
await delay(2000);
66+
equal(pool.threads.length, 2);
67+
68+
const secondTasks = [
69+
pool.run([buffer, 4]),
70+
pool.run([buffer, 4]),
71+
];
72+
equal(pool.threads.length, 2);
73+
74+
75+
76+
const lateThreadIds = await Promise.all(secondTasks);
77+
deepEqual(earlyThreadIds, lateThreadIds);
78+
79+
await Promise.all([pool.run([buffer, 6]), pool.run([buffer, 6]), pool.run([buffer, 6])]);
80+
equal(pool.threads.length, 2);
81+
});

0 commit comments

Comments
 (0)