docs: update benchmarks vs. external pools
[poolifier.git] / README.md
CommitLineData
f2b5671a 1<div align="center">
0feeec4a 2 <img src="./images/logo.png" width="340px" height="266px"/>
ddaa3a76 3</div>
4
3eed0bf4 5<h1 align="center">Node.js Worker_Threads and Cluster Worker Pool</h1>
1d4f79e7
APA
6
7<p align="center">
23fc6cf8
JB
8 <a href="https://github.com/poolifier/poolifier/graphs/commit-activity">
9 <img alt="GitHub commit activity (master)" src="https://img.shields.io/github/commit-activity/m/poolifier/poolifier/master"></a>
1d4f79e7
APA
10 <a href="https://www.npmjs.com/package/poolifier">
11 <img alt="Weekly Downloads" src="https://img.shields.io/npm/dw/poolifier"></a>
d7757502 12 <a href="https://github.com/poolifier/poolifier/actions/workflows/ci.yml">
86f8562e 13 <img alt="Actions Status" src="https://github.com/poolifier/poolifier/actions/workflows/ci.yml/badge.svg"></a>
609edfec 14 <a href="https://sonarcloud.io/dashboard?id=pioardi_poolifier">
22147b67 15 <img alt="Code Coverage" src="https://sonarcloud.io/api/project_badges/measure?project=pioardi_poolifier&metric=coverage"></a>
8076b106
JB
16 <a href="https://sonarcloud.io/dashboard?id=pioardi_poolifier">
17 <img alt="Quality Gate Status" src="https://sonarcloud.io/api/project_badges/measure?project=pioardi_poolifier&metric=alert_status"></a>
1d4f79e7
APA
18 <a href="https://standardjs.com">
19 <img alt="Javascript Standard Style Guide" src="https://img.shields.io/badge/code_style-standard-brightgreen.svg"></a>
20 <a href="https://gitter.im/poolifier/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge">
21 <img alt="Gitter chat" src="https://badges.gitter.im/poolifier/community.svg"></a>
e8a862ca
JB
22 <a href="https://opencollective.com/poolifier">
23 <img alt="Open Collective" src="https://opencollective.com/poolifier/tiers/badge.svg"></a>
1d4f79e7
APA
24 <a href="http://makeapullrequest.com">
25 <img alt="PR Welcome" src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square"></a>
26 <a href="https://img.shields.io/static/v1?label=dependencies&message=no%20dependencies&color=brightgreen">
27 <img alt="No dependencies" src="https://img.shields.io/static/v1?label=dependencies&message=no%20dependencies&color=brightgreen"></a>
1d4f79e7
APA
28</p>
29
74750c7f 30## Why Poolifier?
e76f5485 31
6ec11f90 32Poolifier is used to perform CPU and/or I/O intensive tasks on Node.js servers, it implements worker pools using [worker_threads](https://nodejs.org/api/worker_threads.html) and [cluster](https://nodejs.org/api/cluster.html) Node.js modules.
50aa7901 33With poolifier you can improve your **performance** and resolve problems related to the event loop.
063f8c5b 34Moreover you can execute your tasks using an API designed to improve the **developer experience**.
b492f20e 35Please consult our [general guidelines](#general-guidelines).
e76f5485 36
bd2ff6e0
JB
37- Easy to use :white_check_mark:
38- Performance [benchmarks](./benchmarks/README.md) :white_check_mark:
03babf6f 39- Fixed and dynamic pool size :white_check_mark:
6ec11f90 40- Easy switch from a pool type to another :white_check_mark:
82be29c0 41- No runtime dependencies :white_check_mark:
d0ed34c9 42- Proper integration with Node.js [async_hooks](https://nodejs.org/api/async_hooks.html) :white_check_mark:
aad54ad2 43- Support for CommonJS, ESM, and TypeScript :white_check_mark:
6ec11f90 44- Support for [worker_threads](https://nodejs.org/api/worker_threads.html) and [cluster](https://nodejs.org/api/cluster.html) Node.js modules :white_check_mark:
aad54ad2
JB
45- Support for multiple task functions :white_check_mark:
46- Support for sync and async task functions :white_check_mark:
89a4abfd 47- Tasks distribution strategies :white_check_mark:
84de2e11 48- Lockless tasks queueing :white_check_mark:
72695f86 49- Queued tasks rescheduling:
a6b3272b 50 - Task stealing :white_check_mark:
72695f86 51 - Tasks stealing under back pressure :white_check_mark:
dd951876 52 - Tasks redistribution on worker error :white_check_mark:
b492f20e 53- General guidelines on pool choice :white_check_mark:
82be29c0 54- Error handling out of the box :white_check_mark:
6ec11f90 55- Widely tested :white_check_mark:
82be29c0 56- Active community :white_check_mark:
bd2ff6e0 57- Code quality [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=pioardi_poolifier&metric=bugs)](https://sonarcloud.io/dashboard?id=pioardi_poolifier)
d28c7996
JB
58 [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=pioardi_poolifier&metric=code_smells)](https://sonarcloud.io/dashboard?id=pioardi_poolifier)
59 [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=pioardi_poolifier&metric=duplicated_lines_density)](https://sonarcloud.io/dashboard?id=pioardi_poolifier)
60 [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=pioardi_poolifier&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=pioardi_poolifier)
61 [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=pioardi_poolifier&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=pioardi_poolifier)
62 [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=pioardi_poolifier&metric=sqale_index)](https://sonarcloud.io/dashboard?id=pioardi_poolifier)
bd2ff6e0 63- Code security [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=pioardi_poolifier&metric=security_rating)](https://sonarcloud.io/dashboard?id=pioardi_poolifier) [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=pioardi_poolifier&metric=vulnerabilities)](https://sonarcloud.io/dashboard?id=pioardi_poolifier)
ddaa3a76 64
4f8e444d
JB
65## Table of contents
66
67- [Overview](#overview)
68- [Installation](#installation)
69- [Usage](#usage)
8ea47589 70- [Node.js versions](#nodejs-versions)
4f8e444d
JB
71- [API](#api)
72- [General guidelines](#general-guidelines)
73- [Worker choice strategies](#worker-choice-strategies)
74- [Contribute](#contribute)
75- [Team](#team)
76- [License](#license)
34a572eb 77
50aa7901 78## Overview
13031992 79
22c0d9a2 80Poolifier contains two [worker_threads](https://nodejs.org/api/worker_threads.html#class-worker)/[cluster](https://nodejs.org/api/cluster.html#cluster_class_worker) worker pool implementations, you don't have to deal with [worker_threads](https://nodejs.org/api/worker_threads.html)/[cluster](https://nodejs.org/api/cluster.html) complexity.
03babf6f 81The first implementation is a fixed worker pool, with a defined number of workers that are started at creation time and will be reused.
56bbcb6b 82The second implementation is a dynamic worker pool, with a number of worker started at creation time (these workers will be always active and reused) and other workers created when the load will increase (with an upper limit, these workers will be reused when active), the new created workers will be stopped after a configurable period of inactivity.
22c0d9a2 83You have to implement your worker by extending the _ThreadWorker_ or _ClusterWorker_ class.
50aa7901
S
84
85## Installation
86
87```shell
27c5fb75 88npm install poolifier --save
1a4ec243 89```
1a4ec243 90
50aa7901
S
91## Usage
92
6ec11f90 93You can implement a [worker_threads](https://nodejs.org/api/worker_threads.html#class-worker) worker in a simple way by extending the class _ThreadWorker_:
1a4ec243
APA
94
95```js
96'use strict'
d2eb4964 97const { ThreadWorker } = require('poolifier')
1a4ec243 98
78cea37e 99function yourFunction(data) {
106744f7 100 // this will be executed in the worker thread,
101 // the data will be received by using the execute method
102 return { ok: 1 }
103}
104
50aa7901 105module.exports = new ThreadWorker(yourFunction, {
124119cf 106 maxInactiveTime: 60000
50aa7901 107})
1a4ec243
APA
108```
109
0feeec4a 110Instantiate your pool based on your needs :
1a4ec243
APA
111
112```js
113'use strict'
6961ca9a 114const { DynamicThreadPool, FixedThreadPool, PoolEvents, availableParallelism } = require('poolifier')
1a4ec243 115
2fbe1783 116// a fixed worker_threads pool
6961ca9a 117const pool = new FixedThreadPool(availableParallelism(), './yourWorker.js', {
0eee77cb 118 errorHandler: (e) => console.error(e),
53795b86
JB
119 onlineHandler: () => console.info('worker is online')
120})
1a4ec243 121
2431bdb4 122pool.emitter.on(PoolEvents.ready, () => console.info('Pool is ready'))
53795b86 123pool.emitter.on(PoolEvents.busy, () => console.info('Pool is busy'))
164d950a 124
2fbe1783 125// or a dynamic worker_threads pool
31a7d5be 126const pool = new DynamicThreadPool(Math.floor(availableParallelism() / 2), availableParallelism(), './yourWorker.js', {
0eee77cb 127 errorHandler: (e) => console.error(e),
53795b86
JB
128 onlineHandler: () => console.info('worker is online')
129})
106744f7 130
53795b86 131pool.emitter.on(PoolEvents.full, () => console.info('Pool is full'))
2431bdb4 132pool.emitter.on(PoolEvents.ready, () => console.info('Pool is ready'))
53795b86 133pool.emitter.on(PoolEvents.busy, () => console.info('Pool is busy'))
1a4ec243
APA
134
135// the execute method signature is the same for both implementations,
74ecb519 136// so you can easily switch from one to another
8351c9af 137pool
8923de44 138 .execute()
0eee77cb 139 .then((res) => {
8351c9af
JB
140 console.info(res)
141 })
0eee77cb 142 .catch((err) => {
8351c9af
JB
143 console.error(err)
144 })
1a4ec243
APA
145```
146
6ec11f90 147You can do the same with the classes _ClusterWorker_, _FixedClusterPool_ and _DynamicClusterPool_.
31b90205 148
b0834e9d 149**See [examples](./examples/) for more details**:
b2b02b3d 150
7a923e5b 151- [Javascript](./examples/javascript/)
b2b02b3d 152- [Typescript](./examples/typescript/)
5ba0cd3c 153 - [HTTP client pool](./examples/typescript/http-client-pool/)
9aef1431 154 - [SMTP client pool](./examples/typescript/smtp-client-pool/)
fac9ce96 155 - [HTTP server pool](./examples/typescript/http-server-pool/)
d2bc8d80 156 - [Express worker_threads pool](./examples/typescript/http-server-pool/express-worker_threads/)
15a9c195 157 - [Express cluster pool](./examples/typescript/http-server-pool/express-cluster/)
d0ed34c9 158 - [Express hybrid pool](./examples/typescript/http-server-pool/express-hybrid/)
d2bc8d80
JB
159 - [Fastify worker_threads pool](./examples/typescript/http-server-pool/fastify-worker_threads/)
160 - [Fastify cluster pool](./examples/typescript/http-server-pool/fastify-cluster/)
3b311539 161 - [Fastify hybrid pool](./examples/typescript/http-server-pool/fastify-hybrid/)
9e623684 162 - [WebSocket server pool](./examples/typescript/websocket-server-pool/)
d2bc8d80 163 - [ws worker_threads pool](./examples/typescript/websocket-server-pool/ws-worker_threads/)
72855e92 164 - [ws cluster pool](./examples/typescript/websocket-server-pool/ws-cluster/)
02999424 165 - [ws hybrid pool](./examples/typescript/websocket-server-pool/ws-hybrid/)
1a4ec243 166
6677a3d3 167Remember that workers can only send and receive structured-cloneable data.
deb85c12 168
8ea47589 169## Node.js versions
34a572eb 170
8ea47589 171Node.js versions >= 16.14.x are supported.
1a4ec243 172
b492f20e 173## [API](./docs/api.md)
4680c1b2 174
4f8e444d
JB
175## [General guidelines](./docs/general-guidelines.md)
176
177## [Worker choice strategies](./docs/worker-choice-strategies.md)
48211d04 178
50aa7901 179## Contribute
34a572eb 180
91633990 181Choose your task here [2.6.x](https://github.com/orgs/poolifier/projects/1), propose an idea, a fix, an improvement.
1a4ec243 182
0feeec4a
JB
183See [CONTRIBUTING](CONTRIBUTING.md) guidelines.
184
50aa7901 185## Team
1a4ec243 186
39deb558 187**Creator/Owner:**
39deb558 188
50aa7901
S
189- [**Alessandro Pio Ardizio**](https://github.com/pioardi)
190
191**_Contributors_**
192
193- [**Shinigami92**](https://github.com/Shinigami92)
194- [**Jérôme Benoit**](https://github.com/jerome-benoit)
39deb558 195
50aa7901 196## License
1a4ec243 197
9507c1d4 198[MIT](./LICENSE)