From a87065328fab2b422843a07cd58ab3f5269ed9bc Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Fri, 11 Aug 2023 18:27:47 +0200 Subject: [PATCH] feat: add fastify poolifier integration example MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Reference #790 Signed-off-by: Jérôme Benoit --- .eslintrc.js | 2 + .vscode/settings.json | 1 + CHANGELOG.md | 2 +- README.md | 1 + .../http-server-pool/express/src/main.ts | 15 +- .../http-server-pool/express/src/worker.ts | 14 +- .../fastify/@types/fastify/index.d.ts | 10 + .../http-server-pool/fastify/package.json | 30 ++ .../http-server-pool/fastify/pnpm-lock.yaml | 431 ++++++++++++++++++ .../http-server-pool/fastify/requests.sh | 8 + .../fastify/src/fastify-poolifier.ts | 37 ++ .../http-server-pool/fastify/src/main.ts | 44 ++ .../http-server-pool/fastify/src/types.ts | 19 + .../http-server-pool/fastify/src/worker.ts | 36 ++ .../http-server-pool/fastify/tsconfig.json | 14 + 15 files changed, 654 insertions(+), 10 deletions(-) create mode 100644 examples/typescript/http-server-pool/fastify/@types/fastify/index.d.ts create mode 100644 examples/typescript/http-server-pool/fastify/package.json create mode 100644 examples/typescript/http-server-pool/fastify/pnpm-lock.yaml create mode 100755 examples/typescript/http-server-pool/fastify/requests.sh create mode 100644 examples/typescript/http-server-pool/fastify/src/fastify-poolifier.ts create mode 100644 examples/typescript/http-server-pool/fastify/src/main.ts create mode 100644 examples/typescript/http-server-pool/fastify/src/types.ts create mode 100644 examples/typescript/http-server-pool/fastify/src/worker.ts create mode 100644 examples/typescript/http-server-pool/fastify/tsconfig.json diff --git a/.eslintrc.js b/.eslintrc.js index c5a0992f..eb288bd1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -57,7 +57,9 @@ module.exports = defineConfig({ 'enum', 'errored', 'esm', + 'fastify', 'fibonacci', + 'fp', 'fs', 'inheritDoc', 'jsdoc', diff --git a/.vscode/settings.json b/.vscode/settings.json index 14e93503..5be1f55a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,6 +13,7 @@ "commitlint", "Dependabot", "eventloop", + "Fastify", "FOSS", "Gitter", "inheritDoc", diff --git a/CHANGELOG.md b/CHANGELOG.md index 8761941e..e4840977 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - HTTP client pool examples: fetch, node-fetch and axios with multiple task functions. -- HTTP server pool examples: express. +- HTTP server pool examples: express, fastify. ## [2.6.22] - 2023-08-10 diff --git a/README.md b/README.md index 546cb9ae..d56bb187 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,7 @@ You can do the same with the classes _ClusterWorker_, _FixedClusterPool_ and _Dy - [HTTP client pool](./examples/typescript/http-client-pool/) - [HTTP server pool](./examples/typescript/http-server-pool/) - [Express](./examples/typescript/http-server-pool/express/) + - [Fastify](./examples/typescript/http-server-pool/fastify/) Remember that workers can only send and receive structured-cloneable data. diff --git a/examples/typescript/http-server-pool/express/src/main.ts b/examples/typescript/http-server-pool/express/src/main.ts index 4f94a83e..02e13939 100644 --- a/examples/typescript/http-server-pool/express/src/main.ts +++ b/examples/typescript/http-server-pool/express/src/main.ts @@ -27,8 +27,13 @@ expressApp.all('/api/echo', (req: Request, res: Response) => { .catch(emptyFunction) }) -expressApp.listen(port, () => { - console.info( - `⚡️[express server]: Express server is started at http://localhost:${port}/` - ) -}) +try { + expressApp.listen(port, () => { + console.info( + `⚡️[express server]: Express server is started at http://localhost:${port}/` + ) + }) +} catch (err) { + console.error(err) + process.exit(1) +} diff --git a/examples/typescript/http-server-pool/express/src/worker.ts b/examples/typescript/http-server-pool/express/src/worker.ts index 65fc7437..f006ad48 100644 --- a/examples/typescript/http-server-pool/express/src/worker.ts +++ b/examples/typescript/http-server-pool/express/src/worker.ts @@ -1,14 +1,20 @@ import { ThreadWorker } from 'poolifier' import { type WorkerData, type WorkerResponse } from './types.js' -class RequestHandlerWorker extends ThreadWorker { +class RequestHandlerWorker< + Data extends WorkerData, + Response extends WorkerResponse +> extends ThreadWorker { public constructor () { super({ - echo: (workerData?: WorkerData) => { - return workerData as WorkerResponse + echo: (workerData?: Data) => { + return workerData as unknown as Response } }) } } -export const requestHandlerWorker = new RequestHandlerWorker() +export const requestHandlerWorker = new RequestHandlerWorker< +WorkerData, +WorkerResponse +>() diff --git a/examples/typescript/http-server-pool/fastify/@types/fastify/index.d.ts b/examples/typescript/http-server-pool/fastify/@types/fastify/index.d.ts new file mode 100644 index 00000000..0e43ad26 --- /dev/null +++ b/examples/typescript/http-server-pool/fastify/@types/fastify/index.d.ts @@ -0,0 +1,10 @@ +import type * as fastify from 'fastify' +import { type DynamicThreadPool } from 'poolifier' +import { type WorkerData, type WorkerResponse } from '../../src/types.ts' + +declare module 'fastify' { + export interface FastifyInstance extends fastify.FastifyInstance { + pool: DynamicThreadPool + execute: (data?: WorkerData, name?: string) => Promise + } +} diff --git a/examples/typescript/http-server-pool/fastify/package.json b/examples/typescript/http-server-pool/fastify/package.json new file mode 100644 index 00000000..c42ea0c4 --- /dev/null +++ b/examples/typescript/http-server-pool/fastify/package.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://json.schemastore.org/package", + "name": "express-request-pool", + "version": "1.0.0", + "description": "Express request pool", + "main": "dist/main.js", + "type": "module", + "volta": { + "node": "20.5.1", + "pnpm": "8.6.12" + }, + "scripts": { + "build": "pnpm build:clean && tsc", + "build:clean": "tsc --build --clean", + "start": "node dist/main.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "fastify": "^4.21.0", + "fastify-plugin": "^4.5.1", + "poolifier": "^2.6.22" + }, + "devDependencies": { + "@types/node": "^20.4.9", + "typescript": "^5.1.6" + } +} diff --git a/examples/typescript/http-server-pool/fastify/pnpm-lock.yaml b/examples/typescript/http-server-pool/fastify/pnpm-lock.yaml new file mode 100644 index 00000000..181c4d24 --- /dev/null +++ b/examples/typescript/http-server-pool/fastify/pnpm-lock.yaml @@ -0,0 +1,431 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + fastify: + specifier: ^4.21.0 + version: 4.21.0 + fastify-plugin: + specifier: ^4.5.1 + version: 4.5.1 + poolifier: + specifier: ^2.6.22 + version: 2.6.22 + +devDependencies: + '@types/node': + specifier: ^20.4.9 + version: 20.4.9 + typescript: + specifier: ^5.1.6 + version: 5.1.6 + +packages: + + /@fastify/ajv-compiler@3.5.0: + resolution: {integrity: sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==} + dependencies: + ajv: 8.12.0 + ajv-formats: 2.1.1(ajv@8.12.0) + fast-uri: 2.2.0 + dev: false + + /@fastify/deepmerge@1.3.0: + resolution: {integrity: sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A==} + dev: false + + /@fastify/error@3.3.0: + resolution: {integrity: sha512-dj7vjIn1Ar8sVXj2yAXiMNCJDmS9MQ9XMlIecX2dIzzhjSHCyKo4DdXjXMs7wKW2kj6yvVRSpuQjOZ3YLrh56w==} + dev: false + + /@fastify/fast-json-stringify-compiler@4.3.0: + resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==} + dependencies: + fast-json-stringify: 5.8.0 + dev: false + + /@types/node@20.4.9: + resolution: {integrity: sha512-8e2HYcg7ohnTUbHk8focoklEQYvemQmu9M/f43DZVx43kHn0tE3BY/6gSDxS7k0SprtS0NHvj+L80cGLnoOUcQ==} + dev: true + + /abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + dependencies: + event-target-shim: 5.0.1 + dev: false + + /abstract-logging@2.0.1: + resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} + dev: false + + /ajv-formats@2.1.1(ajv@8.12.0): + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + dependencies: + ajv: 8.12.0 + dev: false + + /ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + dev: false + + /archy@1.0.0: + resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + dev: false + + /atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + dev: false + + /avvio@8.2.1: + resolution: {integrity: sha512-TAlMYvOuwGyLK3PfBb5WKBXZmXz2fVCgv23d6zZFdle/q3gPjmxBaeuC0pY0Dzs5PWMSgfqqEZkrye19GlDTgw==} + dependencies: + archy: 1.0.0 + debug: 4.3.4 + fastq: 1.15.0 + transitivePeerDependencies: + - supports-color + dev: false + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /cookie@0.5.0: + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + engines: {node: '>= 0.6'} + dev: false + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: false + + /event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + dev: false + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: false + + /fast-content-type-parse@1.0.0: + resolution: {integrity: sha512-Xbc4XcysUXcsP5aHUU7Nq3OwvHq97C+WnbkeIefpeYLX+ryzFJlU6OStFJhs6Ol0LkUGpcK+wL0JwfM+FCU5IA==} + dev: false + + /fast-decode-uri-component@1.0.1: + resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} + dev: false + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: false + + /fast-json-stringify@5.8.0: + resolution: {integrity: sha512-VVwK8CFMSALIvt14U8AvrSzQAwN/0vaVRiFFUVlpnXSnDGrSkOAO5MtzyN8oQNjLd5AqTW5OZRgyjoNuAuR3jQ==} + dependencies: + '@fastify/deepmerge': 1.3.0 + ajv: 8.12.0 + ajv-formats: 2.1.1(ajv@8.12.0) + fast-deep-equal: 3.1.3 + fast-uri: 2.2.0 + rfdc: 1.3.0 + dev: false + + /fast-querystring@1.1.2: + resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} + dependencies: + fast-decode-uri-component: 1.0.1 + dev: false + + /fast-redact@3.3.0: + resolution: {integrity: sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ==} + engines: {node: '>=6'} + dev: false + + /fast-uri@2.2.0: + resolution: {integrity: sha512-cIusKBIt/R/oI6z/1nyfe2FvGKVTohVRfvkOhvx0nCEW+xf5NoCXjAHcWp93uOUBchzYcsvPlrapAdX1uW+YGg==} + dev: false + + /fastify-plugin@4.5.1: + resolution: {integrity: sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==} + dev: false + + /fastify@4.21.0: + resolution: {integrity: sha512-tsu4bcwE4HetxqW8prA5fbC9bKHMYDp7jGEDWyzK1l90a3uOaLoIcQbdGcWeODNLVJviQnzh1wvIjTZE3MJFEg==} + dependencies: + '@fastify/ajv-compiler': 3.5.0 + '@fastify/error': 3.3.0 + '@fastify/fast-json-stringify-compiler': 4.3.0 + abstract-logging: 2.0.1 + avvio: 8.2.1 + fast-content-type-parse: 1.0.0 + fast-json-stringify: 5.8.0 + find-my-way: 7.6.2 + light-my-request: 5.10.0 + pino: 8.15.0 + process-warning: 2.2.0 + proxy-addr: 2.0.7 + rfdc: 1.3.0 + secure-json-parse: 2.7.0 + semver: 7.5.4 + tiny-lru: 11.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: false + + /find-my-way@7.6.2: + resolution: {integrity: sha512-0OjHn1b1nCX3eVbm9ByeEHiscPYiHLfhei1wOUU9qffQkk98wE0Lo8VrVYfSGMgnSnDh86DxedduAnBf4nwUEw==} + engines: {node: '>=14'} + dependencies: + fast-deep-equal: 3.1.3 + fast-querystring: 1.1.2 + safe-regex2: 2.0.0 + dev: false + + /forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + dev: false + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false + + /ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + dev: false + + /json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + dev: false + + /light-my-request@5.10.0: + resolution: {integrity: sha512-ZU2D9GmAcOUculTTdH9/zryej6n8TzT+fNGdNtm6SDp5MMMpHrJJkvAdE3c6d8d2chE9i+a//dS9CWZtisknqA==} + dependencies: + cookie: 0.5.0 + process-warning: 2.2.0 + set-cookie-parser: 2.6.0 + dev: false + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: false + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: false + + /on-exit-leak-free@2.1.0: + resolution: {integrity: sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==} + dev: false + + /pino-abstract-transport@1.0.0: + resolution: {integrity: sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==} + dependencies: + readable-stream: 4.4.2 + split2: 4.2.0 + dev: false + + /pino-std-serializers@6.2.2: + resolution: {integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==} + dev: false + + /pino@8.15.0: + resolution: {integrity: sha512-olUADJByk4twxccmAxb1RiGKOSvddHugCV3wkqjyv+3Sooa2KLrmXrKEWOKi0XPCLasRR5jBXxioE1jxUa4KzQ==} + hasBin: true + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.3.0 + on-exit-leak-free: 2.1.0 + pino-abstract-transport: 1.0.0 + pino-std-serializers: 6.2.2 + process-warning: 2.2.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.4.3 + sonic-boom: 3.3.0 + thread-stream: 2.4.0 + dev: false + + /poolifier@2.6.22: + resolution: {integrity: sha512-0pGU1nG8jVEQUb2j1kkiEQ5TdJyHP3a9zFVxF7Q23xHiGM2hpw9BpWvjP0kvE6LmCx0R8ezFDwaXf9nDUOA9gQ==} + engines: {node: '>=16.14.0', pnpm: '>=8.6.0'} + requiresBuild: true + dev: false + + /process-warning@2.2.0: + resolution: {integrity: sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg==} + dev: false + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: false + + /proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + dev: false + + /punycode@2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + dev: false + + /quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + dev: false + + /readable-stream@4.4.2: + resolution: {integrity: sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + dev: false + + /real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + dev: false + + /require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + dev: false + + /ret@0.2.2: + resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} + engines: {node: '>=4'} + dev: false + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: false + + /rfdc@1.3.0: + resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} + dev: false + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false + + /safe-regex2@2.0.0: + resolution: {integrity: sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==} + dependencies: + ret: 0.2.2 + dev: false + + /safe-stable-stringify@2.4.3: + resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} + engines: {node: '>=10'} + dev: false + + /secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + dev: false + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: false + + /set-cookie-parser@2.6.0: + resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} + dev: false + + /sonic-boom@3.3.0: + resolution: {integrity: sha512-LYxp34KlZ1a2Jb8ZQgFCK3niIHzibdwtwNUWKg0qQRzsDoJ3Gfgkf8KdBTFU3SkejDEIlWwnSnpVdOZIhFMl/g==} + dependencies: + atomic-sleep: 1.0.0 + dev: false + + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + dev: false + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /thread-stream@2.4.0: + resolution: {integrity: sha512-xZYtOtmnA63zj04Q+F9bdEay5r47bvpo1CaNqsKi7TpoJHcotUez8Fkfo2RJWpW91lnnaApdpRbVwCWsy+ifcw==} + dependencies: + real-require: 0.2.0 + dev: false + + /tiny-lru@11.0.1: + resolution: {integrity: sha512-iNgFugVuQgBKrqeO/mpiTTgmBsTP0WL6yeuLfLs/Ctf0pI/ixGqIRm8sDCwMcXGe9WWvt2sGXI5mNqZbValmJg==} + engines: {node: '>=12'} + dev: false + + /typescript@5.1.6: + resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.0 + dev: false + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: false diff --git a/examples/typescript/http-server-pool/fastify/requests.sh b/examples/typescript/http-server-pool/fastify/requests.sh new file mode 100755 index 00000000..e5ad31b3 --- /dev/null +++ b/examples/typescript/http-server-pool/fastify/requests.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e + +for ((request=1;request<=60;request++)) +do + time curl -i -H "Content-Type: application/json" -X POST -d '{"key1":"value1", "key2":"value2"}' http://localhost:8080/api/echo +done diff --git a/examples/typescript/http-server-pool/fastify/src/fastify-poolifier.ts b/examples/typescript/http-server-pool/fastify/src/fastify-poolifier.ts new file mode 100644 index 00000000..1ced0510 --- /dev/null +++ b/examples/typescript/http-server-pool/fastify/src/fastify-poolifier.ts @@ -0,0 +1,37 @@ +import { DynamicThreadPool } from 'poolifier' +import { type FastifyPluginCallback } from 'fastify' +import fp from 'fastify-plugin' +import { + type FastifyPoolifierOptions, + type WorkerData, + type WorkerResponse +} from './types.js' + +const fastifyPoolifierPlugin: FastifyPluginCallback = ( + fastify, + options, + done +): void => { + const pool = new DynamicThreadPool( + options.minWorkers, + options.maxWorkers, + options.workerFile, + options + ) + if (!fastify.hasDecorator('pool')) { + fastify.decorate('pool', pool) + } + if (!fastify.hasDecorator('execute')) { + fastify.decorate( + 'execute', + async (data?: WorkerData, name?: string): Promise => + await pool.execute(data, name) + ) + } + done() +} + +export const fastifyPoolifier = fp(fastifyPoolifierPlugin, { + fastify: '4.x', + name: 'fastify-poolifier' +}) diff --git a/examples/typescript/http-server-pool/fastify/src/main.ts b/examples/typescript/http-server-pool/fastify/src/main.ts new file mode 100644 index 00000000..a681d026 --- /dev/null +++ b/examples/typescript/http-server-pool/fastify/src/main.ts @@ -0,0 +1,44 @@ +import { dirname, extname, join } from 'node:path' +import { fileURLToPath } from 'node:url' +import Fastify from 'fastify' +import { availableParallelism } from 'poolifier' +import { fastifyPoolifier } from './fastify-poolifier.js' + +const port = 8080 +const fastify = Fastify({ + logger: true +}) + +const workerFile = join( + dirname(fileURLToPath(import.meta.url)), + `worker${extname(fileURLToPath(import.meta.url))}` +) + +await fastify.register(fastifyPoolifier, { + workerFile, + minWorkers: 1, + maxWorkers: availableParallelism(), + enableTasksQueue: true, + tasksQueueOptions: { + concurrency: 8 + }, + errorHandler: (e: Error) => { + console.error(e) + } +}) + +fastify.all('/api/echo', async (request, reply) => { + await reply.send((await fastify.execute({ body: request.body }, 'echo')).body) +}) + +// fastify.get('/api/factorial/:number', async (request, reply) => { +// const { number } = request.params +// await reply.send((await fastify.execute({ body: { number } }, 'factorial')).body) +// }) + +try { + await fastify.listen({ port }) +} catch (err) { + fastify.log.error(err) + process.exit(1) +} diff --git a/examples/typescript/http-server-pool/fastify/src/types.ts b/examples/typescript/http-server-pool/fastify/src/types.ts new file mode 100644 index 00000000..5c53f106 --- /dev/null +++ b/examples/typescript/http-server-pool/fastify/src/types.ts @@ -0,0 +1,19 @@ +import { type ThreadPoolOptions } from 'poolifier' + +export interface BodyPayload { + number?: number +} + +export interface WorkerData { + body: T +} + +export interface WorkerResponse { + body: T +} + +export interface FastifyPoolifierOptions extends ThreadPoolOptions { + workerFile: string + maxWorkers: number + minWorkers: number +} diff --git a/examples/typescript/http-server-pool/fastify/src/worker.ts b/examples/typescript/http-server-pool/fastify/src/worker.ts new file mode 100644 index 00000000..7589aa6b --- /dev/null +++ b/examples/typescript/http-server-pool/fastify/src/worker.ts @@ -0,0 +1,36 @@ +import { ThreadWorker } from 'poolifier' +import { + type BodyPayload, + type WorkerData, + type WorkerResponse +} from './types.js' + +const factorial: (n: number) => number = n => { + if (n === 0) { + return 1 + } + return factorial(n - 1) * n +} + +class RequestHandlerWorker< + Data extends WorkerData, + Response extends WorkerResponse +> extends ThreadWorker { + public constructor () { + super({ + echo: (workerData?: Data) => { + return workerData as unknown as Response + }, + factorial: (workerData?: Data) => { + return { + body: { number: factorial(workerData?.body?.number as number) } + } as unknown as Response + } + }) + } +} + +export const requestHandlerWorker = new RequestHandlerWorker< +WorkerData, +WorkerResponse +>() diff --git a/examples/typescript/http-server-pool/fastify/tsconfig.json b/examples/typescript/http-server-pool/fastify/tsconfig.json new file mode 100644 index 00000000..82728d1c --- /dev/null +++ b/examples/typescript/http-server-pool/fastify/tsconfig.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "Node16", + "rootDir": "./src", + "outDir": "./dist", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + } +} -- 2.34.1