chore(deps-dev): bump tatami-ng to 0.6.0
[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
29527e83
JB
5<div align="center">
6
7# Node.js Worker_Threads and Cluster Worker Pool
8
9</div>
1d4f79e7 10
2030d177 11<div align="center">
29527e83
JB
12
13[![GitHub commit activity (master)](https://img.shields.io/github/commit-activity/m/poolifier/poolifier/master?color=brightgreen&logo=github)](https://github.com/poolifier/poolifier/graphs/commit-activity)
b7bb8586 14[![Npm Version](https://badgen.net/npm/v/poolifier?icon=npm)](https://www.npmjs.com/package/poolifier)
8be1fc23 15[![JSR Version](https://jsr.io/badges/@poolifier/poolifier)](https://jsr.io/@poolifier/poolifier)
4e91d15c 16[![CI Workflow](https://github.com/poolifier/poolifier/actions/workflows/ci.yml/badge.svg)](https://github.com/poolifier/poolifier/actions/workflows/ci.yml)
58c0dd01
JB
17[![Code Coverage](https://sonarcloud.io/api/project_badges/measure?project=poolifier_poolifier&metric=coverage)](https://sonarcloud.io/dashboard?id=poolifier_poolifier)
18[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=poolifier_poolifier&metric=alert_status)](https://sonarcloud.io/dashboard?id=poolifier_poolifier)
5c75390e 19[![neostandard Javascript Code Style](<https://badgen.net/static/code style/neostandard/green>)](https://github.com/neostandard/neostandard)
67c552d6 20[![Discord](https://badgen.net/discord/online-members/vXxZhyb3b6?icon=discord&label=discord&color=green)](https://discord.gg/vXxZhyb3b6)
29527e83 21[![Open Collective](https://opencollective.com/poolifier/tiers/badge.svg)](https://opencollective.com/poolifier)
ae3ab61d 22[![PRs Welcome](https://badgen.net/static/PRs/welcome/green)](https://makeapullrequest.com)
f0c6203d 23[![No Dependencies](<https://badgen.net/static/dependencies/no dependencies/green>)](<https://badgen.net/static/dependencies/no dependencies/green>)
29527e83 24
2030d177 25</div>
1d4f79e7 26
74750c7f 27## Why Poolifier?
e76f5485 28
6ec11f90 29Poolifier 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 30With poolifier you can improve your **performance** and resolve problems related to the event loop.
063f8c5b 31Moreover you can execute your tasks using an API designed to improve the **developer experience**.
b492f20e 32Please consult our [general guidelines](#general-guidelines).
e76f5485 33
bd2ff6e0 34- Easy to use :white_check_mark:
03babf6f 35- Fixed and dynamic pool size :white_check_mark:
6ec11f90 36- Easy switch from a pool type to another :white_check_mark:
5bc19860 37- Performance [benchmarks](./benchmarks/README.md) :white_check_mark:
82be29c0 38- No runtime dependencies :white_check_mark:
d0ed34c9 39- Proper integration with Node.js [async_hooks](https://nodejs.org/api/async_hooks.html) :white_check_mark:
e30fb225 40- Support for CommonJS, ESM and TypeScript :white_check_mark:
6ec11f90 41- 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:
89a4abfd 42- Tasks distribution strategies :white_check_mark:
84de2e11 43- Lockless tasks queueing :white_check_mark:
72695f86 44- Queued tasks rescheduling:
65542a35 45 - Task stealing on idle :white_check_mark:
72695f86 46 - Tasks stealing under back pressure :white_check_mark:
dd951876 47 - Tasks redistribution on worker error :white_check_mark:
0c7b9e90 48- Support for sync and async task function :white_check_mark:
97dc65d9
JB
49- Support for multiple task functions with per task function queuing priority and tasks distribution strategy :white_check_mark:
50- Support for task functions [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations at runtime :white_check_mark:
b492f20e 51- General guidelines on pool choice :white_check_mark:
82be29c0 52- Error handling out of the box :white_check_mark:
6ec11f90 53- Widely tested :white_check_mark:
82be29c0 54- Active community :white_check_mark:
58c0dd01
JB
55- Code quality [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=poolifier_poolifier&metric=bugs)](https://sonarcloud.io/dashboard?id=poolifier_poolifier)
56 [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=poolifier_poolifier&metric=code_smells)](https://sonarcloud.io/dashboard?id=poolifier_poolifier)
57 [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=poolifier_poolifier&metric=duplicated_lines_density)](https://sonarcloud.io/dashboard?id=poolifier_poolifier)
58 [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=poolifier_poolifier&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=poolifier_poolifier)
59 [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=poolifier_poolifier&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=poolifier_poolifier)
60 [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=poolifier_poolifier&metric=sqale_index)](https://sonarcloud.io/dashboard?id=poolifier_poolifier)
61- Code security [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=poolifier_poolifier&metric=security_rating)](https://sonarcloud.io/dashboard?id=poolifier_poolifier) [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=poolifier_poolifier&metric=vulnerabilities)](https://sonarcloud.io/dashboard?id=poolifier_poolifier)
ddaa3a76 62
4f8e444d
JB
63## Table of contents
64
65- [Overview](#overview)
66- [Installation](#installation)
67- [Usage](#usage)
8ea47589 68- [Node.js versions](#nodejs-versions)
4f8e444d
JB
69- [API](#api)
70- [General guidelines](#general-guidelines)
71- [Worker choice strategies](#worker-choice-strategies)
72- [Contribute](#contribute)
73- [Team](#team)
74- [License](#license)
34a572eb 75
50aa7901 76## Overview
13031992 77
22c0d9a2 78Poolifier 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 79The first implementation is a fixed worker pool, with a defined number of workers that are started at creation time and will be reused.
a36b9e1f 80The 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 newly created workers will be stopped after a configurable period of inactivity.
22c0d9a2 81You have to implement your worker by extending the _ThreadWorker_ or _ClusterWorker_ class.
50aa7901
S
82
83## Installation
84
39c93c16 85### npmjs
b7bb8586 86
50aa7901 87```shell
27c5fb75 88npm install poolifier --save
1a4ec243 89```
1a4ec243 90
39c93c16 91### JSR
b7bb8586
JB
92
93```shell
94npx jsr add @poolifier/poolifier
95```
96
50aa7901
S
97## Usage
98
a087069e 99You can implement a poolifier [worker_threads](https://nodejs.org/api/worker_threads.html#class-worker) worker in a simple way by extending the class _ThreadWorker_:
1a4ec243
APA
100
101```js
d35e5717 102import { ThreadWorker } from 'poolifier'
1a4ec243 103
78cea37e 104function yourFunction(data) {
106744f7 105 // this will be executed in the worker thread,
106 // the data will be received by using the execute method
107 return { ok: 1 }
108}
109
a5844a0f
JB
110export default new ThreadWorker(yourFunction, {
111 maxInactiveTime: 60000,
50aa7901 112})
1a4ec243
APA
113```
114
0feeec4a 115Instantiate your pool based on your needs :
1a4ec243
APA
116
117```js
d35e5717 118import { DynamicThreadPool, FixedThreadPool, PoolEvents, availableParallelism } from 'poolifier'
1a4ec243 119
2fbe1783 120// a fixed worker_threads pool
6961ca9a 121const pool = new FixedThreadPool(availableParallelism(), './yourWorker.js', {
3fd93ff2 122 onlineHandler: () => console.info('worker is online'),
a5844a0f 123 errorHandler: e => console.error(e),
53795b86 124})
1a4ec243 125
8538ea4c
JB
126pool.emitter?.on(PoolEvents.ready, () => console.info('Pool is ready'))
127pool.emitter?.on(PoolEvents.busy, () => console.info('Pool is busy'))
164d950a 128
2fbe1783 129// or a dynamic worker_threads pool
31a7d5be 130const pool = new DynamicThreadPool(Math.floor(availableParallelism() / 2), availableParallelism(), './yourWorker.js', {
3fd93ff2 131 onlineHandler: () => console.info('worker is online'),
a5844a0f 132 errorHandler: e => console.error(e),
53795b86 133})
106744f7 134
8538ea4c
JB
135pool.emitter?.on(PoolEvents.full, () => console.info('Pool is full'))
136pool.emitter?.on(PoolEvents.ready, () => console.info('Pool is ready'))
137pool.emitter?.on(PoolEvents.busy, () => console.info('Pool is busy'))
1a4ec243
APA
138
139// the execute method signature is the same for both implementations,
74ecb519 140// so you can easily switch from one to another
3b4d090f
JB
141try {
142 const res = await pool.execute()
143 console.info(res)
144} catch (err) {
145 console.error(err)
146}
1a4ec243
APA
147```
148
6ec11f90 149You can do the same with the classes _ClusterWorker_, _FixedClusterPool_ and _DynamicClusterPool_.
31b90205 150
b0834e9d 151**See [examples](./examples/) for more details**:
b2b02b3d 152
7a923e5b 153- [Javascript](./examples/javascript/)
b2b02b3d 154- [Typescript](./examples/typescript/)
5ba0cd3c 155 - [HTTP client pool](./examples/typescript/http-client-pool/)
9aef1431 156 - [SMTP client pool](./examples/typescript/smtp-client-pool/)
fac9ce96 157 - [HTTP server pool](./examples/typescript/http-server-pool/)
d2bc8d80 158 - [Express worker_threads pool](./examples/typescript/http-server-pool/express-worker_threads/)
15a9c195 159 - [Express cluster pool](./examples/typescript/http-server-pool/express-cluster/)
d0ed34c9 160 - [Express hybrid pool](./examples/typescript/http-server-pool/express-hybrid/)
d2bc8d80
JB
161 - [Fastify worker_threads pool](./examples/typescript/http-server-pool/fastify-worker_threads/)
162 - [Fastify cluster pool](./examples/typescript/http-server-pool/fastify-cluster/)
3b311539 163 - [Fastify hybrid pool](./examples/typescript/http-server-pool/fastify-hybrid/)
9e623684 164 - [WebSocket server pool](./examples/typescript/websocket-server-pool/)
d2bc8d80 165 - [ws worker_threads pool](./examples/typescript/websocket-server-pool/ws-worker_threads/)
72855e92 166 - [ws cluster pool](./examples/typescript/websocket-server-pool/ws-cluster/)
02999424 167 - [ws hybrid pool](./examples/typescript/websocket-server-pool/ws-hybrid/)
1a4ec243 168
6677a3d3 169Remember that workers can only send and receive structured-cloneable data.
deb85c12 170
8ea47589 171## Node.js versions
34a572eb 172
277c49bf 173Node.js versions >= 18.x.x are supported.
1a4ec243 174
b492f20e 175## [API](./docs/api.md)
4680c1b2 176
4f8e444d
JB
177## [General guidelines](./docs/general-guidelines.md)
178
179## [Worker choice strategies](./docs/worker-choice-strategies.md)
48211d04 180
50aa7901 181## Contribute
34a572eb 182
f097c79b 183Choose your task [here](https://github.com/orgs/poolifier/projects/1), propose an idea, a fix, an improvement.
1a4ec243 184
e6973c72 185See [CONTRIBUTING](./CONTRIBUTING.md) guidelines.
0feeec4a 186
50aa7901 187## Team
1a4ec243 188
39deb558 189**Creator/Owner:**
39deb558 190
50aa7901
S
191- [**Alessandro Pio Ardizio**](https://github.com/pioardi)
192
5c47fa7c 193**Maintainers:**
50aa7901 194
50aa7901 195- [**Jérôme Benoit**](https://github.com/jerome-benoit)
39deb558 196
5c47fa7c
JB
197**Contributors:**
198
199- [**Shinigami92**](https://github.com/Shinigami92)
200
50aa7901 201## License
1a4ec243 202
9507c1d4 203[MIT](./LICENSE)