feat: add ws-cluster-pool example
authorJérôme Benoit <jerome.benoit@sap.com>
Sat, 12 Aug 2023 21:28:47 +0000 (23:28 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Sat, 12 Aug 2023 21:28:47 +0000 (23:28 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
13 files changed:
.eslintrc.js
.github/dependabot.yml
CHANGELOG.md
README.md
examples/typescript/websocket-server-pool/ws-cluster/package.json [new file with mode: 0644]
examples/typescript/websocket-server-pool/ws-cluster/pnpm-lock.yaml [new file with mode: 0644]
examples/typescript/websocket-server-pool/ws-cluster/requests.js [new file with mode: 0644]
examples/typescript/websocket-server-pool/ws-cluster/rollup.config.mjs [new file with mode: 0644]
examples/typescript/websocket-server-pool/ws-cluster/src/main.ts [new file with mode: 0644]
examples/typescript/websocket-server-pool/ws-cluster/src/types.ts [new file with mode: 0644]
examples/typescript/websocket-server-pool/ws-cluster/src/worker.ts [new file with mode: 0644]
examples/typescript/websocket-server-pool/ws-cluster/tsconfig.json [new file with mode: 0644]
examples/typescript/websocket-server-pool/ws-worker_threads/src/main.ts

index 523f20f8c389d47b15b3b45d5072bad47e31c507..a5382d80588c29850bc8b8ede8b30b0e7b24bad0 100644 (file)
@@ -64,6 +64,7 @@ module.exports = defineConfig({
           'fs',
           'inheritDoc',
           'jsdoc',
+          'localhost',
           'microjob',
           'mjs',
           'npx',
@@ -89,6 +90,8 @@ module.exports = defineConfig({
           'unregister',
           'utf8',
           'workerpool',
+          'ws',
+          'wss',
           'wwr'
         ],
         skipIfMatch: ['^@.*', '^plugin:.*']
index a90c3e1ea8dcf760a44cb2245e370f1455f0d04b..ab597d79335b3efe1d2363f8da7124962489fa6e 100644 (file)
@@ -92,3 +92,15 @@ updates:
       - 'pioardi'
       - 'jerome-benoit'
     versioning-strategy: increase
+  - package-ecosystem: 'npm'
+    directory: '/examples/typescript/websocket-server-pool/ws-cluster'
+    schedule:
+      interval: 'daily'
+    labels:
+      - 'dependencies'
+      - 'examples'
+      - 'nocombine'
+    reviewers:
+      - 'pioardi'
+      - 'jerome-benoit'
+    versioning-strategy: increases
index 27a8e48635042cfc6807bd4b147eb187c40cb837..26b642256b2f1f07d7b4f698224edf3f39e1129f 100644 (file)
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+### Added
+
+- HTTP server pool examples: fastify-cluster.
+- WebSocket server pool examples: ws-cluster
+
 ## [2.6.24] - 2023-08-12
 
 ### Added
index dae42f966c92bf195337be630dcd4e06625cc3c7..7c50ad266fccc47af6fda10b139a948cb7227012 100644 (file)
--- a/README.md
+++ b/README.md
@@ -152,6 +152,7 @@ You can do the same with the classes _ClusterWorker_, _FixedClusterPool_ and _Dy
     - [Fastify cluster pool](./examples/typescript/http-server-pool/fastify-cluster/)
   - [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/)
 
 Remember that workers can only send and receive structured-cloneable data.
 
diff --git a/examples/typescript/websocket-server-pool/ws-cluster/package.json b/examples/typescript/websocket-server-pool/ws-cluster/package.json
new file mode 100644 (file)
index 0000000..74a2128
--- /dev/null
@@ -0,0 +1,38 @@
+{
+  "$schema": "https://json.schemastore.org/package",
+  "name": "ws-cluster-pool",
+  "version": "1.0.0",
+  "description": "ws cluster 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": {
+    "poolifier": "^2.6.24",
+    "ws": "^8.13.0"
+  },
+  "devDependencies": {
+    "@rollup/plugin-typescript": "^11.1.2",
+    "@types/node": "^20.4.10",
+    "@types/ws": "^8.5.5",
+    "rollup": "^3.28.0",
+    "rollup-plugin-delete": "^2.0.0",
+    "tslib": "^2.6.1",
+    "typescript": "^5.1.6"
+  },
+  "optionalDependencies": {
+    "bufferutil": "^4.0.7",
+    "utf-8-validate": "^6.0.3"
+  }
+}
diff --git a/examples/typescript/websocket-server-pool/ws-cluster/pnpm-lock.yaml b/examples/typescript/websocket-server-pool/ws-cluster/pnpm-lock.yaml
new file mode 100644 (file)
index 0000000..6485ddb
--- /dev/null
@@ -0,0 +1,501 @@
+lockfileVersion: '6.0'
+
+settings:
+  autoInstallPeers: true
+  excludeLinksFromLockfile: false
+
+dependencies:
+  poolifier:
+    specifier: ^2.6.24
+    version: 2.6.24
+  ws:
+    specifier: ^8.13.0
+    version: 8.13.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
+
+optionalDependencies:
+  bufferutil:
+    specifier: ^4.0.7
+    version: 4.0.7
+  utf-8-validate:
+    specifier: ^6.0.3
+    version: 6.0.3
+
+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
+  '@types/ws':
+    specifier: ^8.5.5
+    version: 8.5.5
+  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:
+
+  /@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
+
+  /@types/ws@8.5.5:
+    resolution: {integrity: sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==}
+    dependencies:
+      '@types/node': 20.4.10
+    dev: true
+
+  /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
+
+  /array-union@2.1.0:
+    resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /balanced-match@1.0.2:
+    resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+    dev: true
+
+  /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
+
+  /bufferutil@4.0.7:
+    resolution: {integrity: sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==}
+    engines: {node: '>=6.14.2'}
+    requiresBuild: true
+    dependencies:
+      node-gyp-build: 4.6.0
+    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
+
+  /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
+
+  /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
+
+  /fastq@1.15.0:
+    resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
+    dependencies:
+      reusify: 1.0.4
+    dev: true
+
+  /fill-range@7.0.1:
+    resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
+    engines: {node: '>=8'}
+    dependencies:
+      to-regex-range: 5.0.1
+    dev: true
+
+  /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
+
+  /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
+
+  /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
+
+  /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
+
+  /node-gyp-build@4.6.0:
+    resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==}
+    hasBin: true
+    requiresBuild: true
+    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
+
+  /poolifier@2.6.24:
+    resolution: {integrity: sha512-3sofqoocsvz7R6LshWJ1FvnjCsHdKytw29gsrVB7AJ0d7jVuE6dMd7ax2O0U03hg+yhxpeBXOaUGO025b40kjA==}
+    engines: {node: '>=16.14.0', pnpm: '>=8.6.0'}
+    requiresBuild: true
+    dev: false
+
+  /queue-microtask@1.2.3:
+    resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+    dev: true
+
+  /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
+
+  /reusify@1.0.4:
+    resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+    engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+    dev: true
+
+  /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
+
+  /slash@3.0.0:
+    resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /supports-preserve-symlinks-flag@1.0.0:
+    resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+    engines: {node: '>= 0.4'}
+    dev: true
+
+  /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
+
+  /utf-8-validate@6.0.3:
+    resolution: {integrity: sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==}
+    engines: {node: '>=6.14.2'}
+    requiresBuild: true
+    dependencies:
+      node-gyp-build: 4.6.0
+    dev: false
+
+  /wrappy@1.0.2:
+    resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+    dev: true
+
+  /ws@8.13.0(bufferutil@4.0.7)(utf-8-validate@6.0.3):
+    resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==}
+    engines: {node: '>=10.0.0'}
+    peerDependencies:
+      bufferutil: ^4.0.1
+      utf-8-validate: '>=5.0.2'
+    peerDependenciesMeta:
+      bufferutil:
+        optional: true
+      utf-8-validate:
+        optional: true
+    dependencies:
+      bufferutil: 4.0.7
+      utf-8-validate: 6.0.3
+    dev: false
diff --git a/examples/typescript/websocket-server-pool/ws-cluster/requests.js b/examples/typescript/websocket-server-pool/ws-cluster/requests.js
new file mode 100644 (file)
index 0000000..1f302a6
--- /dev/null
@@ -0,0 +1,21 @@
+// eslint-disable-next-line import/no-unresolved, n/no-missing-import
+import { WebSocket } from 'ws'
+
+const ws = new WebSocket('ws://localhost:8080')
+
+ws.on('error', console.error)
+
+ws.on('open', () => {
+  for (let i = 0; i < 60; i++) {
+    ws.send(
+      JSON.stringify({ type: 'echo', data: { key1: 'value1', key2: 'value2' } })
+    )
+  }
+  for (let i = 0; i < 60; i++) {
+    ws.send(JSON.stringify({ type: 'factorial', data: { number: 30 } }))
+  }
+})
+
+ws.on('message', message => {
+  console.info('message received: %s', message)
+})
diff --git a/examples/typescript/websocket-server-pool/ws-cluster/rollup.config.mjs b/examples/typescript/websocket-server-pool/ws-cluster/rollup.config.mjs
new file mode 100644 (file)
index 0000000..6bc34ee
--- /dev/null
@@ -0,0 +1,32 @@
+/* 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/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: ['node:path', 'node:url', 'poolifier', 'ws'],
+  plugins: [
+    typescript(),
+    del({
+      targets: ['dist/*']
+    })
+  ]
+}
diff --git a/examples/typescript/websocket-server-pool/ws-cluster/src/main.ts b/examples/typescript/websocket-server-pool/ws-cluster/src/main.ts
new file mode 100644 (file)
index 0000000..ce9eb64
--- /dev/null
@@ -0,0 +1,42 @@
+import { dirname, extname, join } from 'node:path'
+import { fileURLToPath } from 'node:url'
+import { FixedClusterPool, availableParallelism } from 'poolifier'
+import { type WorkerData, type WorkerResponse } from './types.js'
+
+const workerFile = join(
+  dirname(fileURLToPath(import.meta.url)),
+  `worker${extname(fileURLToPath(import.meta.url))}`
+)
+
+const pool = new FixedClusterPool<WorkerData, WorkerResponse>(
+  availableParallelism(),
+  workerFile,
+  {
+    errorHandler: (e: Error) => {
+      console.error(e)
+    }
+  }
+)
+
+// Start one ws server instance per cluster worker in the pool
+for (let i = 1; i <= pool.info.maxSize; i++) {
+  pool
+    .execute({ port: 8080 })
+    .then(response => {
+      if (response.status) {
+        console.info(
+          // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+          `WebSocket server is listening on worker ${i} on port ${response.port}`
+        )
+      } else {
+        console.error(
+          `WebSocket server failed to start on worker ${i}:`,
+          response.error
+        )
+      }
+      return null
+    })
+    .catch(error => {
+      console.error(error)
+    })
+}
diff --git a/examples/typescript/websocket-server-pool/ws-cluster/src/types.ts b/examples/typescript/websocket-server-pool/ws-cluster/src/types.ts
new file mode 100644 (file)
index 0000000..5b3c89a
--- /dev/null
@@ -0,0 +1,23 @@
+export enum MessageType {
+  echo = 'echo',
+  factorial = 'factorial'
+}
+
+export interface MessagePayload<T = unknown> {
+  type: MessageType
+  data: T
+}
+
+export interface DataPayload {
+  number?: number
+}
+
+export interface WorkerData {
+  port: number
+}
+
+export interface WorkerResponse {
+  status: boolean
+  port?: number
+  error?: Error
+}
diff --git a/examples/typescript/websocket-server-pool/ws-cluster/src/worker.ts b/examples/typescript/websocket-server-pool/ws-cluster/src/worker.ts
new file mode 100644 (file)
index 0000000..7d2a36d
--- /dev/null
@@ -0,0 +1,73 @@
+import { ClusterWorker } from 'poolifier'
+import { type RawData, WebSocketServer } from 'ws'
+import {
+  type DataPayload,
+  type MessagePayload,
+  MessageType,
+  type WorkerData,
+  type WorkerResponse
+} from './types.js'
+
+const factorial: (n: number) => number = n => {
+  if (n === 0) {
+    return 1
+  }
+  return factorial(n - 1) * n
+}
+
+const startWebSocketServer = (workerData?: WorkerData): WorkerResponse => {
+  try {
+    const wss = new WebSocketServer({ port: workerData?.port }, () => {
+      console.info(
+        `⚡️[ws server]: WebSocket server is started at ws://localhost:${
+          workerData?.port as number
+        }/`
+      )
+    })
+
+    wss.on('connection', ws => {
+      ws.on('error', console.error)
+      ws.on('message', (message: RawData) => {
+        const { type, data } = JSON.parse(
+          // eslint-disable-next-line @typescript-eslint/no-base-to-string
+          message.toString()
+        ) as MessagePayload<DataPayload>
+        switch (type) {
+          case MessageType.echo:
+            ws.send(
+              JSON.stringify({
+                type: MessageType.echo,
+                data
+              })
+            )
+            break
+          case MessageType.factorial:
+            ws.send(
+              JSON.stringify({
+                type: MessageType.factorial,
+                data: { number: factorial(data.number as number) }
+              })
+            )
+            break
+        }
+      })
+    })
+    return {
+      status: true,
+      port: wss.options.port
+    }
+  } catch (err) {
+    return {
+      status: false,
+      error: err as Error
+    }
+  }
+}
+
+class WebSocketServerWorker extends ClusterWorker<WorkerData, WorkerResponse> {
+  public constructor () {
+    super(startWebSocketServer)
+  }
+}
+
+export const webSocketServerWorker = new WebSocketServerWorker()
diff --git a/examples/typescript/websocket-server-pool/ws-cluster/tsconfig.json b/examples/typescript/websocket-server-pool/ws-cluster/tsconfig.json
new file mode 100644 (file)
index 0000000..57e49a1
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "compilerOptions": {
+    "target": "ES2022",
+    "module": "ES2022",
+    "moduleResolution": "Node16",
+    "verbatimModuleSyntax": true,
+    "rootDir": "./src",
+    "outDir": "./dist",
+    "esModuleInterop": true,
+    "forceConsistentCasingInFileNames": true,
+    "strict": true,
+    "skipLibCheck": true
+  }
+}
index 1eda1e92dd3b8f47ecbde99b9098768388eb92cf..6283759d403047be2837b8322147f0741973adcd 100644 (file)
@@ -5,7 +5,7 @@ import { requestHandlerPool } from './pool.js'
 const port = 8080
 const wss = new WebSocketServer({ port }, () => {
   console.info(
-    `⚡️[ws server]: WebSocket server is started at http://localhost:${port}/`
+    `⚡️[ws server]: WebSocket server is started at ws://localhost:${port}/`
   )
 })