Skip to content

Commit 1cc333c

Browse files
authored
Merge pull request #9 from Edujugon/dev
V2 - Worker parallelizer
2 parents cca9a36 + 8f5ab25 commit 1cc333c

5 files changed

Lines changed: 274 additions & 27 deletions

File tree

README.md

Lines changed: 108 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,30 @@
11
# Node Parallelizer
2-
A NodeJS package for running code in parallel. Initially created to provide multiprocessing in an AWS Lambda function, but it can be used in any NodeJS environment.
2+
A NodeJS package for running code in parallel. Initially created to provide multiprocessing in an **AWS Lambda function**, but it can be used in any NodeJS environment.
33

44
## Supported parallelizers
55
- Child Process
6-
- Worker threads [Coming soon]
6+
- Worker threads
77

88
### Child Process Parallelizer
9-
This parallelizer is specifically designed for processing hundreds or thousands of records in a single invocation when your code performs both CPU-intensive and I/O-intensive operations. It uses the NodeJS [child process module](https://nodejs.org/api/child_process.html) behind the scenes.
9+
This parallelizer is specifically designed for processing hundreds or thousands of records in a single invocation when your code performs both CPU-intensive and **I/O-intensive operations**.
1010

1111
When you call the `runBatch(records)` method in this parallelizer, the package will split the list of records you provide into smaller subsets, and your code will be used to execute each subset in parallel.
1212

13-
## AWS Lambda & Child Process Parallelizer
14-
The package can detect the number of vCPU cores allocated to your Lambda function and maximize their utilization. By default, it generates one child process per vCPU core, but this setting can be customized to meet your specific requirements. Alternatively, you can manually specify the number of child processes the library creates, regardless of the number of vCPU cores available.
13+
It uses the NodeJS [child process module](https://nodejs.org/api/child_process.html) behind the scenes.
14+
15+
### Worker Threads Parallelizer
16+
This parallelizer is specifically designed for processing hundreds or thousands of records in a single invocation when your code performs **CPU-intensive operations**.
17+
18+
When you call the `runBatch(records)` method in this parallelizer, the package will split the list of records you provide into smaller subsets, and your code will be used to execute each subset in parallel.
19+
20+
It uses the NodeJS [worker threads module](https://nodejs.org/api/worker_threads.html) behind the scenes.
21+
22+
## AWS Lambda & Node Parallelizer
23+
This package can detect the number of vCPU cores allocated to your Lambda function and maximize their utilization. By default, it generates one child process/thread per vCPU core, but this setting can be customized to meet your specific requirements. Alternatively, you can manually specify the number of child processes/threads the library creates, regardless of the number of vCPU cores available.
1524

1625
It uses the Lambda function environment `/tmp` folder to create the required module that runs in the child.
1726

18-
When you call the `parallelizerFunction` method outside of the Lambda handler function, it will reuse the child processes across the different invocations within a Lambda instance, improving performance. Furthermore, if the package detects a disconnection of any of the child processes, it will recreate it automatically without affecting the execution.
27+
On the Child Process Parallelizer, when you call the `parallelizerFunction` method outside of the Lambda handler function, it will reuse the child processes across the different invocations within a Lambda instance, minimazing the impact of creating child process on every invocation. Furthermore, if the package detects a disconnection of any of the child processes, it will recreate it automatically without affecting the execution.
1928

2029
## Installation
2130
To add this package to your dependency list, run:
@@ -24,34 +33,37 @@ To add this package to your dependency list, run:
2433
npm i node-parallelizer --save
2534
```
2635
## Usage
27-
### Child Process Parallelizer
28-
#### Class instantiation
29-
`ChildProcess({ tmpPath = '/tmp', maxProcesses = false, processesPerCPU = 1, debug = false })`
36+
37+
<details>
38+
<summary>Child Process Parallelizer (<b>I/O-intensive operations or CPU-intensive operations && I/O-intensive operations</b>)</summary>
39+
40+
#### Class instantiation
41+
`ChildProcess({ tmpPath = '/tmp', maxParallelization = false, parallelizationPerCPU = 1, debug = false })`
3042

3143
**Parameters**
3244
- `tmpPath` (String) (Default value: '/tmp'): The path where the module that runs in the child will be created.
33-
- `maxProcesses` (Number|false) (Default value: false): The maximum number of child processes that will be created. If false, it is based on the CPU cores available.
34-
- `processesPerCPU` (Number) (Default value: 1): If the `maxProcesses` is set to `false`, this parameter defines the amount of processes per CPU.
45+
- `maxParallelization` (Number|false) (Default value: false): The maximum number of child processes that will be created. If false, it is based on the CPU cores available.
46+
- `parallelizationPerCPU` (Number) (Default value: 1): If the `maxParallelization` is set to `false`, this parameter defines the amount of processes per CPU.
3547
- `debug` (Boolean) (Default value: false): Enables the internal logs for debuggin purposes.
3648
#### Main methods
3749
`parallelizerFunction({ filePath, processBatchFunctionName })`
3850

3951
**Parameters**
40-
- `filePath` (String): The absolute path to the file that contains the function that will be executed with the subset.
41-
- `processBatchFunctionName` (String): The name of the function that will be executed with the subset.
52+
- `filePath` (String): The absolute path to the file that contains the function that will be executed in parallel.
53+
- `processBatchFunctionName` (String): The name of the function that will be executed in parallel.
4254

4355
`runBatch(batch)`
4456

4557
**Parameters**
4658
- `batch` (Array): The records you want to process in parallel.
4759

48-
**Returns** (Array): The responses of the child processes.
60+
**Returns** (Array): The child processes' responses.
4961
#### Using child process parallizer in AWS Lambda.
5062
In this example, the repository structure looks like this
5163
```
5264
src/
5365
handler.js
54-
my-child-code.js
66+
parallel.js
5567
serverless.yml
5668
package.json
5769
```
@@ -65,7 +77,7 @@ const { ChildProcess } = require("node-parallelizer");
6577
// Creates a new child process instance.
6678
const childProcess = new ChildProcess();
6779
// Creates child processes based on your code.
68-
childProcess.parallelizerFunction({ filePath: "/var/task/src/my-child-code.js", processBatchFunctionName: 'batchProcessor' });
80+
childProcess.parallelizerFunction({ filePath: "/var/task/src/parallel.js", processBatchFunctionName: 'batchProcessor' });
6981

7082
module.exports.handler = async(event) => {
7183
// Run batch in parallel
@@ -75,11 +87,11 @@ module.exports.handler = async(event) => {
7587
};
7688

7789
```
78-
> Make sure to provide the filePath parameter as an absolute path. In this example, we've included '/var/task/' in the path for the child code, as Lambda deploys your code within that folder.
90+
> Make sure to provide the filePath parameter as an absolute path. In this example, we've included '/var/task/' prefix in the path because Lambda deploys your code within that folder.
7991
8092
The below snippet represents the code you want to run in parallel
8193
```javascript
82-
// my-child-code.js
94+
// parallel.js
8395

8496
const batchProcessor = ({ batch }) => {
8597

@@ -95,6 +107,83 @@ module.exports = { batchProcessor }
95107

96108
```
97109
> Verify that the input signature of your function (in this case, batchProcessor) includes batch as a parameter, as it contains the subset of records that a child process will handle.
110+
111+
</details>
112+
<details>
113+
<summary>Worker Threads Parallelizer (<b>CPU-intensive operations</b>)</summary>
114+
115+
#### Class instantiation
116+
`WorkerThreads({ tmpPath = '/tmp', maxParallelization = false, parallelizationPerCPU = 1, debug = false })`
117+
118+
**Parameters**
119+
- `tmpPath` (String) (Default value: '/tmp'): The path where the module that runs in the thread will be created.
120+
- `maxParallelization` (Number|false) (Default value: false): The maximum number of threads that will be created. If false, it is based on the CPU cores available.
121+
- `parallelizationPerCPU` (Number) (Default value: 1): If the `maxParallelization` is set to `false`, this parameter defines the amount of threads per CPU.
122+
- `debug` (Boolean) (Default value: false): Enables the internal logs for debuggin purposes.
123+
#### Main methods
124+
`parallelizerFunction({ filePath, processBatchFunctionName })`
125+
126+
**Parameters**
127+
- `filePath` (String): The absolute path to the file that contains the function that will be executed in parallel.
128+
- `processBatchFunctionName` (String): The name of the function that will be executed in parallel.
129+
130+
`runBatch(batch)`
131+
132+
**Parameters**
133+
- `batch` (Array): The records you want to process in parallel.
134+
135+
**Returns** (Array): The thread's responses.
136+
#### Using worker threads parallizer in AWS Lambda.
137+
In this example, the repository structure looks like this
138+
```
139+
src/
140+
handler.js
141+
parallel.js
142+
serverless.yml
143+
package.json
144+
```
145+
146+
The below snippet represents your Lambda handler
147+
```javascript
148+
// handler.js
149+
150+
const { WorkerThreads } = require("node-parallelizer");
151+
152+
// Creates a new child process instance.
153+
const threads = new WorkerThreads();
154+
// Creates child processes based on your code.
155+
threads.parallelizerFunction({ filePath: "/var/task/src/parallel.js", processBatchFunctionName: 'batchProcessor' });
156+
157+
module.exports.handler = async(event) => {
158+
// Run batch in parallel
159+
const responses = await threads.runBatch(event.Records);
160+
161+
console.log(responses);
162+
};
163+
164+
```
165+
> Make sure to provide the filePath parameter as an absolute path. In this example, we've included '/var/task/' prefix in the path because Lambda deploys your code within that folder.
166+
167+
The below snippet represents the code you want to run in parallel
168+
```javascript
169+
// parallel.js
170+
171+
const batchProcessor = ({ batch }) => {
172+
173+
//
174+
// HERE YOUR CODE
175+
//
176+
177+
return { success: true, count: batch.length }
178+
}
179+
180+
181+
module.exports = { batchProcessor }
182+
183+
```
184+
> Verify that the input signature of your function (in this case, batchProcessor) includes batch as a parameter, as it contains the subset of records that a child process will handle.
185+
186+
</details>
98187

99188
## Contribution
100-
We welcome contributions to this project. If you are interested in contributing, please feel free to submit a pull request.
189+
We welcome contributions to this project. If you are interested in contributing, please feel free to submit a pull request.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "node-parallelizer",
3-
"version": "1.2.0",
3+
"version": "2.0.0",
44
"description": "A NodeJS package for running code in parallel. Initially created to provide multiprocessing in an AWS Lambda function, but it can be used in any NodeJS environment.",
55
"main": "src/index.js",
66
"scripts": {

src/child-process.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ const os = require("os");
55
const fs = require('fs');
66
const crypto = require('crypto');
77

8-
const childFileName = "child-process-child-file.js";
8+
const childFileName = "child-process-file";
99

1010
class ChildProcess {
11-
constructor({ tmpPath = '/tmp', maxProcesses = false, processesPerCPU = 1, debug = false, generateStats = false, generateChildStats = false } = {}) {
11+
constructor({ tmpPath = '/tmp', maxParallelization = false, parallelizationPerCPU = 1, debug = false, generateStats = false, generateChildStats = false } = {}) {
1212
const uniqueId = crypto.randomBytes(16).toString('hex');
1313

1414
this.tmpPath = `${tmpPath}/${childFileName}-${uniqueId}.js`;
1515
this.childFile = null;
1616
this.childProcesses = [];
17-
this.maxProcesses = maxProcesses;
18-
this.processesPerCPU = processesPerCPU;
17+
this.maxParallelization = maxParallelization;
18+
this.parallelizationPerCPU = parallelizationPerCPU;
1919

2020
this.processesCount = 1;
2121
this.debug = debug;
@@ -38,7 +38,7 @@ class ChildProcess {
3838
}
3939

4040
_createChildProcesses() {
41-
this.processesCount = (typeof this.maxProcesses === 'number') ? this.maxProcesses : this._getProcessesCount();
41+
this.processesCount = (typeof this.maxParallelization === 'number') ? this.maxParallelization : this._getProcessesCount();
4242

4343
for (let id = 0; id < this.processesCount; id++) {
4444
this.childProcesses.push(this._createFork());
@@ -164,7 +164,7 @@ class ChildProcess {
164164

165165
_getProcessesCount() {
166166
const cpuData = os.cpus();
167-
return cpuData.length * this.processesPerCPU;
167+
return cpuData.length * this.parallelizationPerCPU;
168168
}
169169

170170
_createFork() {

src/index.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
11
const ChildProcess = require("./child-process");
2+
const WorkerThreads = require("./worker-thread");
23

3-
module.exports = { ChildProcess };
4+
const PARALLELIZER_CHILD = 'child-process';
5+
const PARALLELIZER_THREADS = 'worker-threads';
6+
class Parallelizer {
7+
constructor(params) {
8+
const parallelizer = params.type;
9+
10+
if(parallelizer === PARALLELIZER_CHILD) {
11+
return new ChildProcess(params);
12+
}else if(parallelizer === PARALLELIZER_THREADS) {
13+
return new WorkerThreads(params);
14+
}
15+
}
16+
}
17+
module.exports = { ChildProcess, WorkerThreads, Parallelizer };

0 commit comments

Comments
 (0)