From 3b3115396965edad0cf3fefc4f9081977310da34 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sun, 13 Aug 2023 16:26:08 +0200 Subject: [PATCH] feat: add fastify hybrid pools example MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit closes #119 and #790 Signed-off-by: Jérôme Benoit --- .github/dependabot.yml | 12 + CHANGELOG.md | 2 +- README.md | 1 + .../typescript/http-client-pool/src/pool.ts | 2 +- .../express-worker_threads/src/pool.ts | 2 +- .../fastify-cluster/src/main.ts | 2 +- .../fastify-hybrid/@types/fastify/index.d.ts | 17 + .../fastify-hybrid/package.json | 34 + .../fastify-hybrid/pnpm-lock.yaml | 825 ++++++++++++++++++ .../fastify-hybrid/requests.sh | 14 + .../fastify-hybrid/rollup.config.mjs | 36 + .../fastify-hybrid/src/fastify-poolifier.ts | 49 ++ .../fastify-hybrid/src/fastify-worker.ts | 61 ++ .../fastify-hybrid/src/main.ts | 35 + .../src/request-handler-worker.ts | 36 + .../fastify-hybrid/src/types.ts | 28 + .../fastify-hybrid/tsconfig.json | 16 + .../fastify-worker_threads/src/main.ts | 2 +- .../fastify-worker_threads/tsconfig.json | 1 + .../ws-cluster/src/main.ts | 2 +- .../ws-cluster/src/worker.ts | 4 +- .../ws-worker_threads/src/pool.ts | 2 +- 22 files changed, 1173 insertions(+), 10 deletions(-) create mode 100644 examples/typescript/http-server-pool/fastify-hybrid/@types/fastify/index.d.ts create mode 100644 examples/typescript/http-server-pool/fastify-hybrid/package.json create mode 100644 examples/typescript/http-server-pool/fastify-hybrid/pnpm-lock.yaml create mode 100755 examples/typescript/http-server-pool/fastify-hybrid/requests.sh create mode 100644 examples/typescript/http-server-pool/fastify-hybrid/rollup.config.mjs create mode 100644 examples/typescript/http-server-pool/fastify-hybrid/src/fastify-poolifier.ts create mode 100644 examples/typescript/http-server-pool/fastify-hybrid/src/fastify-worker.ts create mode 100644 examples/typescript/http-server-pool/fastify-hybrid/src/main.ts create mode 100644 examples/typescript/http-server-pool/fastify-hybrid/src/request-handler-worker.ts create mode 100644 examples/typescript/http-server-pool/fastify-hybrid/src/types.ts create mode 100644 examples/typescript/http-server-pool/fastify-hybrid/tsconfig.json diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ab597d79..6c957f88 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -80,6 +80,18 @@ updates: - 'pioardi' - 'jerome-benoit' versioning-strategy: increase + - package-ecosystem: 'npm' + directory: '/examples/typescript/http-server-pool/fastify-hybrid' + schedule: + interval: 'daily' + labels: + - 'dependencies' + - 'examples' + - 'nocombine' + reviewers: + - 'pioardi' + - 'jerome-benoit' + versioning-strategy: increase - package-ecosystem: 'npm' directory: '/examples/typescript/websocket-server-pool/ws-worker_threads' schedule: diff --git a/CHANGELOG.md b/CHANGELOG.md index 26b64225..8c5e44f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- HTTP server pool examples: fastify-cluster. +- HTTP server pool examples: fastify-cluster, fastify-hybrid. - WebSocket server pool examples: ws-cluster ## [2.6.24] - 2023-08-12 diff --git a/README.md b/README.md index 7c50ad26..f2f67d83 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,7 @@ You can do the same with the classes _ClusterWorker_, _FixedClusterPool_ and _Dy - [Express worker_threads pool](./examples/typescript/http-server-pool/express-worker_threads/) - [Fastify worker_threads pool](./examples/typescript/http-server-pool/fastify-worker_threads/) - [Fastify cluster pool](./examples/typescript/http-server-pool/fastify-cluster/) + - [Fastify hybrid pool](./examples/typescript/http-server-pool/fastify-hybrid/) - [WebSocket server pool](./examples/typescript/websocket-server-pool/) - [ws worker_threads pool](./examples/typescript/websocket-server-pool/ws-worker_threads/) - [ws cluster pool](./examples/typescript/websocket-server-pool/ws-cluster/) diff --git a/examples/typescript/http-client-pool/src/pool.ts b/examples/typescript/http-client-pool/src/pool.ts index f1306adf..3d64150a 100644 --- a/examples/typescript/http-client-pool/src/pool.ts +++ b/examples/typescript/http-client-pool/src/pool.ts @@ -18,7 +18,7 @@ export const httpClientPool = new DynamicThreadPool( concurrency: 8 }, errorHandler: (e: Error) => { - console.error(e) + console.error('Thread worker error:', e) } } ) diff --git a/examples/typescript/http-server-pool/express-worker_threads/src/pool.ts b/examples/typescript/http-server-pool/express-worker_threads/src/pool.ts index af2a216d..6ae00292 100644 --- a/examples/typescript/http-server-pool/express-worker_threads/src/pool.ts +++ b/examples/typescript/http-server-pool/express-worker_threads/src/pool.ts @@ -21,6 +21,6 @@ WorkerResponse concurrency: 8 }, errorHandler: (e: Error) => { - console.error(e) + console.error('Thread worker error:', e) } }) diff --git a/examples/typescript/http-server-pool/fastify-cluster/src/main.ts b/examples/typescript/http-server-pool/fastify-cluster/src/main.ts index ec117cbc..0ac8f5ce 100644 --- a/examples/typescript/http-server-pool/fastify-cluster/src/main.ts +++ b/examples/typescript/http-server-pool/fastify-cluster/src/main.ts @@ -29,7 +29,7 @@ const pool = new FixedClusterPool( }) }, errorHandler: (e: Error) => { - console.error(e) + console.error('Cluster worker error:', e) } } ) diff --git a/examples/typescript/http-server-pool/fastify-hybrid/@types/fastify/index.d.ts b/examples/typescript/http-server-pool/fastify-hybrid/@types/fastify/index.d.ts new file mode 100644 index 00000000..a9959239 --- /dev/null +++ b/examples/typescript/http-server-pool/fastify-hybrid/@types/fastify/index.d.ts @@ -0,0 +1,17 @@ +import type * as fastify from 'fastify' +import { type DynamicThreadPool } from 'poolifier' +import { + type ThreadWorkerData, + type ThreadWorkerResponse +} from '../../src/types.ts' + +declare module 'fastify' { + export interface FastifyInstance extends fastify.FastifyInstance { + pool: DynamicThreadPool + execute: ( + data?: ThreadWorkerData, + name?: string, + transferList?: TransferListItem[] + ) => Promise + } +} diff --git a/examples/typescript/http-server-pool/fastify-hybrid/package.json b/examples/typescript/http-server-pool/fastify-hybrid/package.json new file mode 100644 index 00000000..40f57664 --- /dev/null +++ b/examples/typescript/http-server-pool/fastify-hybrid/package.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://json.schemastore.org/package", + "name": "fastify-hybrid-pool", + "version": "1.0.0", + "description": "Fastify hybrid pool", + "main": "dist/main.js", + "type": "module", + "volta": { + "node": "20.5.1", + "pnpm": "8.6.12" + }, + "scripts": { + "build": "rollup --config", + "start": "node dist/main.cjs", + "start:esm": "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.24" + }, + "devDependencies": { + "@rollup/plugin-typescript": "^11.1.2", + "@types/node": "^20.4.10", + "rollup": "^3.28.0", + "rollup-plugin-delete": "^2.0.0", + "tslib": "^2.6.1", + "typescript": "^5.1.6" + } +} diff --git a/examples/typescript/http-server-pool/fastify-hybrid/pnpm-lock.yaml b/examples/typescript/http-server-pool/fastify-hybrid/pnpm-lock.yaml new file mode 100644 index 00000000..5f2379b8 --- /dev/null +++ b/examples/typescript/http-server-pool/fastify-hybrid/pnpm-lock.yaml @@ -0,0 +1,825 @@ +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.24 + version: 2.6.24 + +devDependencies: + '@rollup/plugin-typescript': + specifier: ^11.1.2 + version: 11.1.2(rollup@3.28.0)(tslib@2.6.1)(typescript@5.1.6) + '@types/node': + specifier: ^20.4.10 + version: 20.4.10 + rollup: + specifier: ^3.28.0 + version: 3.28.0 + rollup-plugin-delete: + specifier: ^2.0.0 + version: 2.0.0 + tslib: + specifier: ^2.6.1 + version: 2.6.1 + 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 + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@rollup/plugin-typescript@11.1.2(rollup@3.28.0)(tslib@2.6.1)(typescript@5.1.6): + resolution: {integrity: sha512-0ghSOCMcA7fl1JM+0gYRf+Q/HWyg+zg7/gDSc+fRLmlJWcW5K1I+CLRzaRhXf4Y3DRyPnnDo4M2ktw+a6JcDEg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.14.0||^3.0.0 + tslib: '*' + typescript: '>=3.7.0' + peerDependenciesMeta: + rollup: + optional: true + tslib: + optional: true + dependencies: + '@rollup/pluginutils': 5.0.2(rollup@3.28.0) + resolve: 1.22.4 + rollup: 3.28.0 + tslib: 2.6.1 + typescript: 5.1.6 + dev: true + + /@rollup/pluginutils@5.0.2(rollup@3.28.0): + resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.1 + estree-walker: 2.0.2 + picomatch: 2.3.1 + rollup: 3.28.0 + dev: true + + /@types/estree@1.0.1: + resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} + dev: true + + /@types/glob@7.2.0: + resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} + dependencies: + '@types/minimatch': 5.1.2 + '@types/node': 20.4.10 + dev: true + + /@types/minimatch@5.1.2: + resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} + dev: true + + /@types/node@20.4.10: + resolution: {integrity: sha512-vwzFiiy8Rn6E0MtA13/Cxxgpan/N6UeNYR9oUu6kuJWxu6zCk98trcDp8CBhbtaeuq9SykCmXkFr2lWLoPcvLg==} + 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 + + /aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + dev: true + + /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 + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /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 + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /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 + + /del@5.1.0: + resolution: {integrity: sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==} + engines: {node: '>=8'} + dependencies: + globby: 10.0.2 + graceful-fs: 4.2.11 + is-glob: 4.0.3 + is-path-cwd: 2.2.0 + is-path-inside: 3.0.3 + p-map: 3.0.0 + rimraf: 3.0.2 + slash: 3.0.0 + dev: true + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: true + + /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-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /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 + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /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 + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /globby@10.0.2: + resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==} + engines: {node: '>=8'} + dependencies: + '@types/glob': 7.2.0 + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.1 + glob: 7.2.3 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true + + /has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + dev: true + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false + + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: true + + /indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true + + /ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + dev: false + + /is-core-module@2.13.0: + resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} + dependencies: + has: 1.0.3 + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-path-cwd@2.2.0: + resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} + engines: {node: '>=6'} + dev: true + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /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 + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /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 + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true + + /p-map@3.0.0: + resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} + engines: {node: '>=8'} + dependencies: + aggregate-error: 3.1.0 + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /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.24: + resolution: {integrity: sha512-3sofqoocsvz7R6LshWJ1FvnjCsHdKytw29gsrVB7AJ0d7jVuE6dMd7ax2O0U03hg+yhxpeBXOaUGO025b40kjA==} + 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 + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /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 + + /resolve@1.22.4: + resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==} + hasBin: true + dependencies: + is-core-module: 2.13.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /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'} + + /rfdc@1.3.0: + resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} + dev: false + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /rollup-plugin-delete@2.0.0: + resolution: {integrity: sha512-/VpLMtDy+8wwRlDANuYmDa9ss/knGsAgrDhM+tEwB1npHwNu4DYNmDfUL55csse/GHs9Q+SMT/rw9uiaZ3pnzA==} + engines: {node: '>=10'} + dependencies: + del: 5.1.0 + dev: true + + /rollup@3.28.0: + resolution: {integrity: sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /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 + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + + /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 + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /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 + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /tslib@2.6.1: + resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==} + dev: true + + /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 + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: false diff --git a/examples/typescript/http-server-pool/fastify-hybrid/requests.sh b/examples/typescript/http-server-pool/fastify-hybrid/requests.sh new file mode 100755 index 00000000..1438f0c3 --- /dev/null +++ b/examples/typescript/http-server-pool/fastify-hybrid/requests.sh @@ -0,0 +1,14 @@ +#!/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 + + +for ((request=1;request<=60;request++)) +do + time curl -i http://localhost:8080/api/factorial/30 +done diff --git a/examples/typescript/http-server-pool/fastify-hybrid/rollup.config.mjs b/examples/typescript/http-server-pool/fastify-hybrid/rollup.config.mjs new file mode 100644 index 00000000..0b93ba20 --- /dev/null +++ b/examples/typescript/http-server-pool/fastify-hybrid/rollup.config.mjs @@ -0,0 +1,36 @@ +/* eslint-disable n/no-unpublished-import */ +import typescript from '@rollup/plugin-typescript' +import del from 'rollup-plugin-delete' + +export default { + input: [ + 'src/main.ts', + 'src/fastify-worker.ts', + 'src/request-handler-worker.ts' + ], + strictDeprecations: true, + output: [ + { + format: 'cjs', + dir: 'dist', + sourcemap: true, + entryFileNames: '[name].cjs', + preserveModules: true, + preserveModulesRoot: 'src' + }, + { + format: 'esm', + dir: 'dist', + sourcemap: true, + preserveModules: true, + preserveModulesRoot: 'src' + } + ], + external: ['fastify', 'fastify-plugin', 'node:path', 'node:url', 'poolifier'], + plugins: [ + typescript(), + del({ + targets: ['dist/*'] + }) + ] +} diff --git a/examples/typescript/http-server-pool/fastify-hybrid/src/fastify-poolifier.ts b/examples/typescript/http-server-pool/fastify-hybrid/src/fastify-poolifier.ts new file mode 100644 index 00000000..6e3a1dbf --- /dev/null +++ b/examples/typescript/http-server-pool/fastify-hybrid/src/fastify-poolifier.ts @@ -0,0 +1,49 @@ +import type { TransferListItem } from 'worker_threads' +import { DynamicThreadPool, availableParallelism } from 'poolifier' +import { type FastifyPluginCallback } from 'fastify' +import fp from 'fastify-plugin' +import { + type FastifyPoolifierOptions, + type ThreadWorkerData, + type ThreadWorkerResponse +} from './types.js' + +const fastifyPoolifierPlugin: FastifyPluginCallback = ( + fastify, + options, + done +) => { + options = { + ...{ + minWorkers: 1, + maxWorkers: availableParallelism() + }, + ...options + } + const pool = new DynamicThreadPool( + options.minWorkers as number, + options.maxWorkers as number, + options.workerFile, + options + ) + if (!fastify.hasDecorator('pool')) { + fastify.decorate('pool', pool) + } + if (!fastify.hasDecorator('execute')) { + fastify.decorate( + 'execute', + async ( + data?: ThreadWorkerData, + name?: string, + transferList?: TransferListItem[] + ): Promise => + await pool.execute(data, name, transferList) + ) + } + done() +} + +export const fastifyPoolifier = fp(fastifyPoolifierPlugin, { + fastify: '4.x', + name: 'fastify-poolifier' +}) diff --git a/examples/typescript/http-server-pool/fastify-hybrid/src/fastify-worker.ts b/examples/typescript/http-server-pool/fastify-hybrid/src/fastify-worker.ts new file mode 100644 index 00000000..1eca6aac --- /dev/null +++ b/examples/typescript/http-server-pool/fastify-hybrid/src/fastify-worker.ts @@ -0,0 +1,61 @@ +import type { AddressInfo } from 'node:net' +import { dirname, extname, join } from 'node:path' +import { fileURLToPath } from 'node:url' +import { ClusterWorker, availableParallelism } from 'poolifier' +import Fastify from 'fastify' +import type { ClusterWorkerData, ClusterWorkerResponse } from './types.js' +import { fastifyPoolifier } from './fastify-poolifier.js' + +const startFastify = async ( + workerData?: ClusterWorkerData +): Promise => { + const { port } = workerData as ClusterWorkerData + const fastify = Fastify({ + logger: true + }) + + const requestHandlerWorkerFile = join( + dirname(fileURLToPath(import.meta.url)), + `request-handler-worker${extname(fileURLToPath(import.meta.url))}` + ) + + await fastify.register(fastifyPoolifier, { + workerFile: requestHandlerWorkerFile, + maxWorkers: Math.round(availableParallelism() / 2), + enableTasksQueue: true, + tasksQueueOptions: { + concurrency: 8 + }, + errorHandler: (e: Error) => { + fastify.log.error('Thread worker error', e) + } + }) + + fastify.all('/api/echo', async request => { + return (await fastify.execute({ body: request.body }, 'echo')).body + }) + + fastify.get<{ + Params: { number: number } + }>('/api/factorial/:number', async request => { + const { number } = request.params + return (await fastify.execute({ body: { number } }, 'factorial')).body + }) + + await fastify.listen({ port }) + return { + status: true, + port: (fastify.server.address() as AddressInfo).port + } +} + +class FastifyWorker extends ClusterWorker< +ClusterWorkerData, +ClusterWorkerResponse +> { + public constructor () { + super(startFastify) + } +} + +export const fastifyWorker = new FastifyWorker() diff --git a/examples/typescript/http-server-pool/fastify-hybrid/src/main.ts b/examples/typescript/http-server-pool/fastify-hybrid/src/main.ts new file mode 100644 index 00000000..8a17f893 --- /dev/null +++ b/examples/typescript/http-server-pool/fastify-hybrid/src/main.ts @@ -0,0 +1,35 @@ +import { dirname, extname, join } from 'node:path' +import { fileURLToPath } from 'node:url' +import { FixedClusterPool, availableParallelism } from 'poolifier' +import type { ClusterWorkerData, ClusterWorkerResponse } from './types.js' + +const fastifyWorkerFile = join( + dirname(fileURLToPath(import.meta.url)), + `fastify-worker${extname(fileURLToPath(import.meta.url))}` +) + +const pool = new FixedClusterPool( + Math.round(availableParallelism() / 2), + fastifyWorkerFile, + { + onlineHandler: () => { + pool + .execute({ port: 8080 }) + .then(response => { + if (response.status) { + console.info( + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + `Fastify is listening on worker on port ${response.port}` + ) + } + return null + }) + .catch(error => { + console.error('Fastify failed to start on worker:', error) + }) + }, + errorHandler: (e: Error) => { + console.error('Cluster worker error:', e) + } + } +) diff --git a/examples/typescript/http-server-pool/fastify-hybrid/src/request-handler-worker.ts b/examples/typescript/http-server-pool/fastify-hybrid/src/request-handler-worker.ts new file mode 100644 index 00000000..1b35b44b --- /dev/null +++ b/examples/typescript/http-server-pool/fastify-hybrid/src/request-handler-worker.ts @@ -0,0 +1,36 @@ +import { ThreadWorker } from 'poolifier' +import { + type BodyPayload, + type ThreadWorkerData, + type ThreadWorkerResponse +} from './types.js' + +const factorial: (n: number) => number = n => { + if (n === 0) { + return 1 + } + return factorial(n - 1) * n +} + +class RequestHandlerWorker< + Data extends ThreadWorkerData, + Response extends ThreadWorkerResponse +> 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< +ThreadWorkerData, +ThreadWorkerResponse +>() diff --git a/examples/typescript/http-server-pool/fastify-hybrid/src/types.ts b/examples/typescript/http-server-pool/fastify-hybrid/src/types.ts new file mode 100644 index 00000000..cdd67845 --- /dev/null +++ b/examples/typescript/http-server-pool/fastify-hybrid/src/types.ts @@ -0,0 +1,28 @@ +import type { ThreadPoolOptions } from 'poolifier' + +export interface ClusterWorkerData { + port: number +} + +export interface ClusterWorkerResponse { + status: boolean + port?: number +} + +export interface BodyPayload { + number?: number +} + +export interface ThreadWorkerData { + body: T +} + +export interface ThreadWorkerResponse { + body: T +} + +export interface FastifyPoolifierOptions extends ThreadPoolOptions { + workerFile: string + maxWorkers?: number + minWorkers?: number +} diff --git a/examples/typescript/http-server-pool/fastify-hybrid/tsconfig.json b/examples/typescript/http-server-pool/fastify-hybrid/tsconfig.json new file mode 100644 index 00000000..963a067f --- /dev/null +++ b/examples/typescript/http-server-pool/fastify-hybrid/tsconfig.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "Node16", + "verbatimModuleSyntax": true, + "rootDir": "./src", + "outDir": "./dist", + "typeRoots": ["./node_modules/@types", "./@types"], + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + } +} diff --git a/examples/typescript/http-server-pool/fastify-worker_threads/src/main.ts b/examples/typescript/http-server-pool/fastify-worker_threads/src/main.ts index 7db0b519..cc647a0f 100644 --- a/examples/typescript/http-server-pool/fastify-worker_threads/src/main.ts +++ b/examples/typescript/http-server-pool/fastify-worker_threads/src/main.ts @@ -24,7 +24,7 @@ await fastify.register(fastifyPoolifier, { concurrency: 8 }, errorHandler: (e: Error) => { - fastify.log.error(e) + fastify.log.error('Thread worker error:', e) } }) diff --git a/examples/typescript/http-server-pool/fastify-worker_threads/tsconfig.json b/examples/typescript/http-server-pool/fastify-worker_threads/tsconfig.json index 57e49a1c..963a067f 100644 --- a/examples/typescript/http-server-pool/fastify-worker_threads/tsconfig.json +++ b/examples/typescript/http-server-pool/fastify-worker_threads/tsconfig.json @@ -7,6 +7,7 @@ "verbatimModuleSyntax": true, "rootDir": "./src", "outDir": "./dist", + "typeRoots": ["./node_modules/@types", "./@types"], "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, diff --git a/examples/typescript/websocket-server-pool/ws-cluster/src/main.ts b/examples/typescript/websocket-server-pool/ws-cluster/src/main.ts index d2ab87b1..9a77c055 100644 --- a/examples/typescript/websocket-server-pool/ws-cluster/src/main.ts +++ b/examples/typescript/websocket-server-pool/ws-cluster/src/main.ts @@ -29,7 +29,7 @@ const pool = new FixedClusterPool( }) }, errorHandler: (e: Error) => { - console.error(e) + console.error('Cluster worker error', e) } } ) diff --git a/examples/typescript/websocket-server-pool/ws-cluster/src/worker.ts b/examples/typescript/websocket-server-pool/ws-cluster/src/worker.ts index f4fc3b7f..b489415f 100644 --- a/examples/typescript/websocket-server-pool/ws-cluster/src/worker.ts +++ b/examples/typescript/websocket-server-pool/ws-cluster/src/worker.ts @@ -19,9 +19,7 @@ const startWebSocketServer = (workerData?: WorkerData): WorkerResponse => { const { port } = workerData as WorkerData const wss = new WebSocketServer({ port }, () => { console.info( - `⚡️[ws server]: WebSocket server is started on worker at ws://localhost:${ - port - }/` + `⚡️[ws server]: WebSocket server is started on worker at ws://localhost:${port}/` ) }) diff --git a/examples/typescript/websocket-server-pool/ws-worker_threads/src/pool.ts b/examples/typescript/websocket-server-pool/ws-worker_threads/src/pool.ts index b29c6d18..39cba844 100644 --- a/examples/typescript/websocket-server-pool/ws-worker_threads/src/pool.ts +++ b/examples/typescript/websocket-server-pool/ws-worker_threads/src/pool.ts @@ -21,6 +21,6 @@ WorkerResponse concurrency: 8 }, errorHandler: (e: Error) => { - console.error(e) + console.error('Thread worker error:', e) } }) -- 2.34.1