Skip to content

Commit

Permalink
new options - resourceLimits
Browse files Browse the repository at this point in the history
  • Loading branch information
Rafal Augustyniak committed Dec 17, 2021
1 parent b2d5552 commit 19e8725
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 9 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.4.0] - 2021-12-03

### Added

- new options `resourceLimits`, See [Node.js new Worker options](https://nodejs.org/api/worker_threads.html#worker_threads_new_worker_filename_options)

## [2.3.1] - 2021-05-05

### Changed
Expand Down
16 changes: 16 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ Describes a WorkerNodes options.
* [.taskMaxRetries](#WorkerNodesOptions+taskMaxRetries) : <code>Number</code>
* [.workerEndurance](#WorkerNodesOptions+workerEndurance) : <code>Number</code>
* [.workerStopTimeout](#WorkerNodesOptions+workerStopTimeout) : <code>Number</code>
* [.resourceLimits](#WorkerNodesOptions+resourceLimits) : <code>Object</code>

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

Expand Down Expand Up @@ -191,6 +192,21 @@ The timeout value (in milliseconds) for the worker to stop before sending SIGKIL

**Kind**: instance property of [<code>WorkerNodesOptions</code>](#WorkerNodesOptions)
**Default**: <code>100</code>
<a name="WorkerNodesOptions+resourceLimits"></a>

### options.resourceLimits : <code>Object</code>
Provides the set of JS engine resource constraints inside this Worker thread.

**Kind**: instance property of [<code>WorkerNodesOptions</code>](#WorkerNodesOptions)
**Properties**

| Name | Type | Description |
| --- | --- | --- |
| maxYoungGenerationSizeMb | <code>Number</code> | The maximum size of a heap space for recently created objects |
| maxOldGenerationSizeMb | <code>Number</code> | The maximum size of the main heap in MB |
| codeRangeSizeMb | <code>Number</code> | The size of a pre-allocated memory range used for generated code |
| stackSizeMb | <code>Number</code> | The default maximum stack size for the thread. Small values may lead to unusable Worker instances |


## Example

Expand Down
112 changes: 112 additions & 0 deletions e2e/resource-limits.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
const test = require('ava');

const WorkerNodes = require('../');
const { fixture } = require('./utils');

test('should set maxYoungGenerationSizeMb', async t => {
// given
const workerNodes = new WorkerNodes(fixture('process-info'), {
autoStart: true,
maxWorkers: 2,
minWorkers: 2,
resourceLimits: {
maxYoungGenerationSizeMb: 20
}
});

// when
await workerNodes.ready();

const workersList = workerNodes.getUsedWorkers();

// then
workersList.forEach(worker => {
if (!worker.resourceLimits) {
// resourceLimits is unsupported before node 12, skipping
return t.true(true);
}

t.true(worker.resourceLimits.maxYoungGenerationSizeMb === 20)
});
});

test('should set maxOldGenerationSizeMb', async t => {
// given
const workerNodes = new WorkerNodes(fixture('process-info'), {
autoStart: true,
maxWorkers: 2,
minWorkers: 2,
resourceLimits: {
maxOldGenerationSizeMb: 300
}
});

// when
await workerNodes.ready();

const workersList = workerNodes.getUsedWorkers();

// then
workersList.forEach(worker => {
if (!worker.resourceLimits) {
// resourceLimits is unsupported before node 12, skipping
return t.true(true);
}

t.true(worker.resourceLimits.maxOldGenerationSizeMb === 300)
});
});

test('should set codeRangeSizeMb', async t => {
// given
const workerNodes = new WorkerNodes(fixture('process-info'), {
autoStart: true,
maxWorkers: 2,
minWorkers: 2,
resourceLimits: {
codeRangeSizeMb: 1
}
});

// when
await workerNodes.ready();

const workersList = workerNodes.getUsedWorkers();

// then
workersList.forEach(worker => {
if (!worker.resourceLimits) {
// resourceLimits is unsupported before node 12, skipping
return t.true(true);
}

t.true(worker.resourceLimits.codeRangeSizeMb === 1)
});
});

test('should set stackSizeMb', async t => {
// given
const workerNodes = new WorkerNodes(fixture('process-info'), {
autoStart: true,
maxWorkers: 2,
minWorkers: 2,
resourceLimits: {
stackSizeMb: 8
}
});

// when
await workerNodes.ready();

const workersList = workerNodes.getUsedWorkers();

// then
workersList.forEach(worker => {
if (!worker.resourceLimits) {
// resourceLimits is unsupported before node 12, skipping
return t.true(true);
}

t.true(worker.resourceLimits.stackSizeMb === 8)
});
});
17 changes: 15 additions & 2 deletions lib/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class WorkerNodesOptions {
taskTimeout = Infinity,
taskMaxRetries = 0,
workerEndurance = Infinity,
workerStopTimeout = 100
workerStopTimeout = 100,
resourceLimits = {}
} = {}) {
/**
* Whether should initialize the workers before a first call.
Expand Down Expand Up @@ -115,6 +116,17 @@ class WorkerNodesOptions {
* @default 100
*/
this.workerStopTimeout = Number(workerStopTimeout);

/**
* Provides the set of JS engine resource constraints inside this Worker thread.
*
* @type {Object}
* @property {Number} maxYoungGenerationSizeMb - The maximum size of a heap space for recently created objects
* @property {Number} maxOldGenerationSizeMb - The maximum size of the main heap in MB
* @property {Number} codeRangeSizeMb - The size of a pre-allocated memory range used for generated code
* @property {Number} stackSizeMb - The default maximum stack size for the thread. Small values may lead to unusable Worker instances
*/
this.resourceLimits = resourceLimits;
}

/**
Expand All @@ -139,7 +151,8 @@ class WorkerNodesOptions {
maxTasks: this.maxTasksPerWorker,
endurance: this.workerEndurance,
stopTimeout: this.workerStopTimeout,
asyncWorkerInitialization: this.asyncWorkerInitialization
asyncWorkerInitialization: this.asyncWorkerInitialization,
resourceLimits: this.resourceLimits
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions lib/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const ProcessResponse = messages.Response;
const workerSerial = new Sequence(1);

class Worker extends EventEmitter {
constructor({ srcFilePath, maxTasks, endurance, stopTimeout, asyncWorkerInitialization }) {
constructor({ srcFilePath, maxTasks, endurance, stopTimeout, asyncWorkerInitialization, resourceLimits }) {
super();

this.id = workerSerial.nextValue();
Expand All @@ -21,7 +21,7 @@ class Worker extends EventEmitter {
this.isTerminating = false;
this.isProcessAlive = false;

const process = this.process = new WorkerProcess(srcFilePath, { stopTimeout, asyncWorkerInitialization });
const process = this.process = new WorkerProcess(srcFilePath, { stopTimeout, asyncWorkerInitialization, resourceLimits });

process.once('ready', () => {
this.isProcessAlive = true;
Expand Down
6 changes: 4 additions & 2 deletions lib/worker/process.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ const worker = require('worker_threads');
const EventEmitter = require('events');

class WorkerProcess extends EventEmitter {
constructor(modulePath, { asyncWorkerInitialization }) {
constructor(modulePath, { asyncWorkerInitialization, resourceLimits }) {
super();

const child = new worker.Worker(require.resolve('./child-loader'));
const child = new worker.Worker(require.resolve('./child-loader'), {
resourceLimits,
});

child.once('message', () => {
// report readiness on a first message received from the child
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "worker-nodes",
"version": "2.3.1",
"version": "2.4.0",
"description": "A library to run cpu-intensive tasks without blocking the event loop.",
"keywords": [
"workers",
Expand Down

0 comments on commit 19e8725

Please sign in to comment.