From f9120de0bc45929ab19aa4eb724ebc3b6159a0b3 Mon Sep 17 00:00:00 2001 From: Weyoss Date: Sat, 23 Mar 2024 12:42:38 +0100 Subject: [PATCH] refactor!: rewrite and optimize worker logic, clean up --- package-lock.json | 573 +++++------------- package.json | 7 +- scripts/test.sh | 5 +- src/event-bus/event-bus-redis.ts | 2 +- src/event-bus/event-bus.ts | 2 +- src/event-bus/types/event-bus.ts | 2 +- src/redis-client/clients/ioredis-client.ts | 2 +- src/redis-client/clients/node-redis-client.ts | 2 +- .../clients/redis-client-abstract.ts | 2 +- src/redis-client/types/redis-client.ts | 2 +- src/worker/errors/worker-thread.error.ts | 10 +- src/worker/types/index.ts | 1 + src/worker/types/worker-thread.ts | 71 +++ src/worker/types/worker.ts | 59 +- src/worker/worker-callable.ts | 16 +- src/worker/worker-resource-group.ts | 12 +- src/worker/worker-runnable.ts | 36 +- src/worker/worker-thread.ts | 138 ----- .../worker-thread/worker-thread-callable.ts | 49 ++ .../worker-thread/worker-thread-message.ts | 53 ++ .../worker-thread/worker-thread-runnable.ts | 58 ++ src/worker/worker-thread/worker-thread.ts | 80 +++ src/worker/worker.ts | 49 +- tests/event/test00001.test.ts | 2 +- tests/event/test00002.test.ts | 4 +- tests/redis-client/common.ts | 4 +- tests/worker/test00001.test.ts | 4 +- tests/worker/test00002.test.ts | 4 +- tests/worker/test00003.test.ts | 16 +- tests/worker/test00004.test.ts | 12 +- tests/worker/test00005.test.ts | 12 +- tests/worker/test00006.test.ts | 17 +- tests/worker/test00007.test.ts | 15 +- tests/worker/test00008.test.ts | 16 +- tests/worker/test00009.test.ts | 17 +- tests/worker/test00010.test.ts | 19 +- tests/worker/test00011.test.ts | 8 +- tests/worker/test00013.test.ts | 2 - .../workers/runnable/runnable1.worker.ts | 16 +- .../workers/runnable/runnable2.worker.ts | 16 +- tests/worker/workers/worker-error.worker.ts | 2 +- tests/worker/workers/worker-ok.worker.ts | 9 +- 42 files changed, 689 insertions(+), 737 deletions(-) create mode 100644 src/worker/types/worker-thread.ts delete mode 100644 src/worker/worker-thread.ts create mode 100644 src/worker/worker-thread/worker-thread-callable.ts create mode 100644 src/worker/worker-thread/worker-thread-message.ts create mode 100644 src/worker/worker-thread/worker-thread-runnable.ts create mode 100644 src/worker/worker-thread/worker-thread.ts diff --git a/package-lock.json b/package-lock.json index 9fa79dd..55ee058 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "uuid": "8.3.2" }, "devDependencies": { - "@jest/globals": "^29.7.0", + "@jest/globals": "29.7.0", "@types/bluebird": "3.5.36", "@types/debug": "4.1.7", "@types/jest": "29.5.8", @@ -31,7 +31,7 @@ "eslint": "8.53.0", "eslint-config-prettier": "9.0.0", "eslint-plugin-prettier": "5.0.1", - "husky": "7.0.4", + "husky": "9.0.11", "jest": "29.7.0", "lint-staged": "11.1.2", "prettier": "3.0.3", @@ -52,127 +52,56 @@ } }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz", + "integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", - "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.3.tgz", + "integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.1", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.9", - "@babel/parser": "^7.23.9", - "@babel/template": "^7.23.9", - "@babel/traverse": "^7.23.9", - "@babel/types": "^7.23.9", + "@babel/helpers": "^7.24.1", + "@babel/parser": "^7.24.1", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -197,14 +126,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", + "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", "dev": true, "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -271,12 +200,12 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", "dev": true, "dependencies": { - "@babel/types": "^7.22.15" + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -302,9 +231,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", "dev": true, "engines": { "node": ">=6.9.0" @@ -335,9 +264,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -362,28 +291,29 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz", - "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", + "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", "dev": true, "dependencies": { - "@babel/template": "^7.23.9", - "@babel/traverse": "^7.23.9", - "@babel/types": "^7.23.9" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -461,9 +391,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", - "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -533,12 +463,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", - "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -635,12 +565,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", - "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", + "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -649,48 +579,34 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", - "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", - "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.23.9", - "@babel/types": "^7.23.9" + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", - "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.9", - "@babel/types": "^7.23.9", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -708,9 +624,9 @@ } }, "node_modules/@babel/types": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", - "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.23.4", @@ -727,32 +643,6 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -1229,32 +1119,32 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" @@ -1267,9 +1157,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", - "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1360,38 +1250,6 @@ "@sinonjs/commons": "^3.0.0" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1540,9 +1398,9 @@ "dev": true }, "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/stack-utils": { @@ -1788,17 +1646,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -1901,14 +1748,6 @@ "node": ">= 8" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2010,23 +1849,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - } - }, "node_modules/babel-preset-current-node-syntax": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", @@ -2100,9 +1922,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, "funding": [ { @@ -2119,8 +1941,8 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, @@ -2182,9 +2004,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001580", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001580.tgz", - "integrity": "sha512-mtj5ur2FFPZcCEpXFy8ADXbDACuNFXg6mxVDqp7tqooX6l3zwm+d8EPoeOSIFRDvHs8qu7/SLFOGniULkcH2iA==", + "version": "1.0.30001600", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz", + "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==", "dev": true, "funding": [ { @@ -2404,14 +2226,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2488,17 +2302,6 @@ "node": ">=8" } }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -2546,9 +2349,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.646", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.646.tgz", - "integrity": "sha512-vThkQ0JuF45qT/20KbRgM56lV7IuGt7SjhawQ719PDHzhP84KAO1WJoaxgCoAffKHK47FmVKP1Fqizx7CwK1SA==", + "version": "1.4.715", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.715.tgz", + "integrity": "sha512-XzWNH4ZSa9BwVUQSDorPWAUQ5WGuYz7zJUNpNif40zFCiCl20t8zgylmreNmn26h5kiyw2lg7RfTmeMBsDklqg==", "dev": true }, "node_modules/emittery": { @@ -2592,9 +2395,9 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" @@ -2909,9 +2712,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -2981,9 +2784,9 @@ } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, "node_modules/fs.realpath": { @@ -3157,9 +2960,9 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "dependencies": { "function-bind": "^1.1.2" @@ -3184,24 +2987,24 @@ } }, "node_modules/husky": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", - "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.0.11.tgz", + "integrity": "sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==", "dev": true, "bin": { - "husky": "lib/bin.js" + "husky": "bin.mjs" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/typicode" } }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" @@ -3434,14 +3237,14 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", - "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", + "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", "dev": true, "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" }, @@ -3478,9 +3281,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -4363,14 +4166,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -4507,9 +4302,9 @@ } }, "node_modules/nan": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", - "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", + "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", "optional": true }, "node_modules/natural-compare": { @@ -4905,9 +4700,9 @@ } }, "node_modules/pure-rand": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", - "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "dev": true, "funding": [ { @@ -4970,14 +4765,6 @@ "node": ">=4" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -5126,9 +4913,9 @@ "optional": true }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -5451,62 +5238,17 @@ } }, "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, "engines": { - "node": ">=16.13.0" + "node": ">=16" }, "peerDependencies": { "typescript": ">=4.2.0" } }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -5685,14 +5427,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/v8-to-istanbul": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", @@ -5817,17 +5551,6 @@ "node": ">=12" } }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 2b4638f..ece0d06 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,8 @@ "import": "./dist/esm/index.js", "require": "./dist/cjs/index.js", "types": "./dist/types/index.d.ts" - } + }, + "./package.json": "./package.json" }, "typesVersions": { "*": { @@ -59,7 +60,7 @@ "uuid": "8.3.2" }, "devDependencies": { - "@jest/globals": "^29.7.0", + "@jest/globals": "29.7.0", "@types/bluebird": "3.5.36", "@types/debug": "4.1.7", "@types/jest": "29.5.8", @@ -71,7 +72,7 @@ "eslint": "8.53.0", "eslint-config-prettier": "9.0.0", "eslint-plugin-prettier": "5.0.1", - "husky": "7.0.4", + "husky": "9.0.11", "jest": "29.7.0", "lint-staged": "11.1.2", "prettier": "3.0.3", diff --git a/scripts/test.sh b/scripts/test.sh index 6e0eead..d27bea3 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -11,7 +11,6 @@ set -x set -e export NODE_ENV=test -DIRNAME=$(dirname "$0") - -. "${DIRNAME}"/build.sh +export NODE_OPTIONS="$NODE_OPTIONS --trace-warnings" +npm run build jest --runInBand --verbose --collectCoverage "$@" \ No newline at end of file diff --git a/src/event-bus/event-bus-redis.ts b/src/event-bus/event-bus-redis.ts index d4211c2..7d2ced1 100644 --- a/src/event-bus/event-bus-redis.ts +++ b/src/event-bus/event-bus-redis.ts @@ -119,7 +119,7 @@ export class EventBusRedis return this; } - shutDown(cb: ICallback) { + shutdown(cb: ICallback) { if (this.connected) { async.waterfall( [ diff --git a/src/event-bus/event-bus.ts b/src/event-bus/event-bus.ts index 22fce15..31541de 100644 --- a/src/event-bus/event-bus.ts +++ b/src/event-bus/event-bus.ts @@ -91,7 +91,7 @@ export class EventBus return this; } - shutDown(cb: ICallback) { + shutdown(cb: ICallback) { if (this.connected) this.connected = false; cb(); } diff --git a/src/event-bus/types/event-bus.ts b/src/event-bus/types/event-bus.ts index 2b11574..d28199d 100644 --- a/src/event-bus/types/event-bus.ts +++ b/src/event-bus/types/event-bus.ts @@ -19,5 +19,5 @@ export type TEventBusEvent = TEventEmitterEvent & { export interface IEventBus extends IEventEmitter { - shutDown(cb: ICallback): void; + shutdown(cb: ICallback): void; } diff --git a/src/redis-client/clients/ioredis-client.ts b/src/redis-client/clients/ioredis-client.ts index 135c31a..66ce8e7 100644 --- a/src/redis-client/clients/ioredis-client.ts +++ b/src/redis-client/clients/ioredis-client.ts @@ -389,7 +389,7 @@ export class IoredisClient extends RedisClientAbstract { } } - shutDown(cb: ICallback = () => void 0): void { + shutdown(cb: ICallback = () => void 0): void { if (!this.connectionClosed) { this.client.once('end', cb); this.client.quit(); diff --git a/src/redis-client/clients/node-redis-client.ts b/src/redis-client/clients/node-redis-client.ts index 72847cd..16d95ec 100644 --- a/src/redis-client/clients/node-redis-client.ts +++ b/src/redis-client/clients/node-redis-client.ts @@ -517,7 +517,7 @@ export class NodeRedisClient extends RedisClientAbstract { } } - shutDown(cb: ICallback = () => void 0): void { + shutdown(cb: ICallback = () => void 0): void { if (!this.connectionClosed) { this.client.once('end', cb); this.client.quit(); diff --git a/src/redis-client/clients/redis-client-abstract.ts b/src/redis-client/clients/redis-client-abstract.ts index 5fb71fb..63786c1 100644 --- a/src/redis-client/clients/redis-client-abstract.ts +++ b/src/redis-client/clients/redis-client-abstract.ts @@ -322,7 +322,7 @@ export abstract class RedisClientAbstract abstract end(flush: boolean): void; - abstract shutDown(cb: ICallback): void; + abstract shutdown(cb: ICallback): void; abstract getInfo(cb: ICallback): void; diff --git a/src/redis-client/types/redis-client.ts b/src/redis-client/types/redis-client.ts index 8924741..da4272a 100644 --- a/src/redis-client/types/redis-client.ts +++ b/src/redis-client/types/redis-client.ts @@ -246,7 +246,7 @@ export interface IRedisClient extends EventEmitter { end(flush: boolean): void; - shutDown(cb: ICallback): void; + shutdown(cb: ICallback): void; getInfo(cb: ICallback): void; diff --git a/src/worker/errors/worker-thread.error.ts b/src/worker/errors/worker-thread.error.ts index aa95a7d..99271fa 100644 --- a/src/worker/errors/worker-thread.error.ts +++ b/src/worker/errors/worker-thread.error.ts @@ -8,17 +8,17 @@ */ import { - EWorkerThreadExecutionCode, - EWorkerThreadExitCode, - TWorkerThreadMessage, + EWorkerThreadChildExecutionCode, + EWorkerThreadChildExitCode, + TWorkerThreadChildMessage, } from '../types/index.js'; import { WorkerError } from './worker-error.js'; export class WorkerThreadError extends WorkerError { - constructor(msg: TWorkerThreadMessage) { + constructor(msg: TWorkerThreadChildMessage) { const { code, error } = msg; const messageStr = `Error code: ${ - EWorkerThreadExitCode[code] ?? EWorkerThreadExecutionCode[code] + EWorkerThreadChildExitCode[code] ?? EWorkerThreadChildExecutionCode[code] }.${error ? ` Cause: ${error.name}(${error.message})` : ''}`; super(messageStr); } diff --git a/src/worker/types/index.ts b/src/worker/types/index.ts index c6b8ccb..5504e04 100644 --- a/src/worker/types/index.ts +++ b/src/worker/types/index.ts @@ -8,3 +8,4 @@ */ export * from './worker.js'; +export * from './worker-thread.js'; diff --git a/src/worker/types/worker-thread.ts b/src/worker/types/worker-thread.ts new file mode 100644 index 0000000..199fc9a --- /dev/null +++ b/src/worker/types/worker-thread.ts @@ -0,0 +1,71 @@ +/* + * Copyright (c) + * Weyoss + * https://github.com/weyoss + * + * This source code is licensed under the MIT license found in the LICENSE file + * in the root directory of this source tree. + */ + +import { EWorkerType } from './worker.js'; + +export interface IWorkerThreadData { + type: EWorkerType; + filename: string; + initialPayload: unknown; +} + +export enum EWorkerThreadChildExitCode { + WORKER_DATA_REQUIRED = 100, + INVALID_WORKER_TYPE, + FILE_IMPORT_ERROR, + UNCAUGHT_EXCEPTION, + FILE_EXTENSION_ERROR, + FILE_READ_ERROR, + TERMINATED, +} + +export enum EWorkerThreadChildExecutionCode { + OK = 200, + PROCESSING_ERROR, + PROCESSING_CAUGHT_ERROR, +} + +export type TWorkerThreadChildMessageCode = + | EWorkerThreadChildExitCode + | EWorkerThreadChildExecutionCode; + +export type TWorkerThreadChildError = { + name: string; + message: string; +}; + +export type TWorkerThreadChildMessage = { + code: TWorkerThreadChildMessageCode; + data?: Data; + error?: TWorkerThreadChildError | null; +}; + +export enum EWorkerThreadParentMessage { + CALL, + RUN, + SHUTDOWN, +} + +export type TWorkerThreadParentMessageCall = { + type: EWorkerThreadParentMessage.CALL; + payload: unknown; +}; + +export type TWorkerThreadParentMessageRun = { + type: EWorkerThreadParentMessage.RUN; +}; + +export type TWorkerThreadParentMessageShutdown = { + type: EWorkerThreadParentMessage.SHUTDOWN; +}; + +export type TWorkerThreadParentMessage = + | TWorkerThreadParentMessageCall + | TWorkerThreadParentMessageRun + | TWorkerThreadParentMessageShutdown; diff --git a/src/worker/types/worker.ts b/src/worker/types/worker.ts index 7b3c3ef..cb02041 100644 --- a/src/worker/types/worker.ts +++ b/src/worker/types/worker.ts @@ -14,49 +14,24 @@ export enum EWorkerType { RUNNABLE, } -// eslint-disable-next-line -export type TWorkerFn = (...args: [...any[], ICallback]) => void; // type-coverage:ignore-line - -export interface IWorkerRunnable { - run(initialPayload: Payload, cb: ICallback): void; +export type TWorkerCallableFunction = ( + args: unknown, + cb: ICallback, +) => void; + +export type TWorkerRunnableFunctionFactory = ( + initialPayload: unknown, +) => IWorkerRunnable; + +export type TWorkerFunction = + | TWorkerRunnableFunctionFactory + | TWorkerCallableFunction; + +export interface IWorkerRunnable { + run(cb: ICallback): void; + shutdown(cb: ICallback): void; } export interface IWorkerCallable { - call(payload: Payload, cb: ICallback): void; -} - -export interface IWorkerData { - type: EWorkerType; - filename: string; -} - -export enum EWorkerThreadExitCode { - WORKER_DATA_REQUIRED = 100, - INVALID_WORKER_TYPE, - FILE_IMPORT_ERROR, - UNCAUGHT_EXCEPTION, - FILE_EXTENSION_ERROR, - FILE_READ_ERROR, - TERMINATED, + call(args: Payload, cb: ICallback): void; } - -export enum EWorkerThreadExecutionCode { - OK = 200, - PROCESSING_ERROR, - PROCESSING_CAUGHT_ERROR, -} - -export type TWorkerThreadMessageCode = - | EWorkerThreadExitCode - | EWorkerThreadExecutionCode; - -export type TWorkerThreadError = { - name: string; - message: string; -}; - -export type TWorkerThreadMessage = { - code: TWorkerThreadMessageCode; - data?: unknown; - error?: TWorkerThreadError | null; -}; diff --git a/src/worker/worker-callable.ts b/src/worker/worker-callable.ts index 73006a8..749a499 100644 --- a/src/worker/worker-callable.ts +++ b/src/worker/worker-callable.ts @@ -8,22 +8,30 @@ */ import { ICallback } from '../common/index.js'; -import { EWorkerType, IWorkerCallable } from './types/index.js'; import { WorkerPayloadRequiredError } from './errors/index.js'; +import { + EWorkerThreadParentMessage, + EWorkerType, + IWorkerCallable, +} from './types/index.js'; import { Worker } from './worker.js'; export class WorkerCallable - extends Worker + extends Worker implements IWorkerCallable { protected readonly type: EWorkerType = EWorkerType.CALLABLE; + constructor(workerFilename: string) { + super(workerFilename); + } + call(payload: Payload, cb: ICallback) { if (payload === null || payload === undefined) { cb(new WorkerPayloadRequiredError()); } else { - // @ts-expect-error reply data type is known only at runtime - this.exec(payload, cb); + this.registerEvents(cb); + this.postMessage({ type: EWorkerThreadParentMessage.CALL, payload }); } } } diff --git a/src/worker/worker-resource-group.ts b/src/worker/worker-resource-group.ts index dea889d..12c2a74 100644 --- a/src/worker/worker-resource-group.ts +++ b/src/worker/worker-resource-group.ts @@ -28,8 +28,7 @@ export class WorkerResourceGroup extends Runnable { protected readonly locker; protected readonly redisClient; protected readonly logger; - protected workers: { instance: WorkerRunnable; payload: unknown }[] = - []; + protected workers: WorkerRunnable[] = []; protected runWorkersLocked = false; constructor( @@ -77,8 +76,7 @@ export class WorkerResourceGroup extends Runnable { async.each( this.workers, (worker, _, done) => { - const { instance, payload } = worker; - instance.run(payload, done); + worker.run(done); }, (err) => { this.runWorkersLocked = false; @@ -94,7 +92,7 @@ export class WorkerResourceGroup extends Runnable { async.each( this.workers, (worker, _, done) => { - worker.instance.shutDown(() => done()); + worker.shutdown(() => done()); }, () => { this.workers = []; @@ -129,9 +127,9 @@ export class WorkerResourceGroup extends Runnable { } addWorker = (filename: string, payload: unknown): void => { - const worker = new WorkerRunnable(filename); + const worker = new WorkerRunnable(filename, payload); worker.on('worker.error', (err) => this.handleError(err)); - this.workers.push({ instance: worker, payload }); + this.workers.push(worker); }; loadFromDir = ( diff --git a/src/worker/worker-runnable.ts b/src/worker/worker-runnable.ts index b628e4e..e494fe4 100644 --- a/src/worker/worker-runnable.ts +++ b/src/worker/worker-runnable.ts @@ -8,7 +8,11 @@ */ import { ICallback } from '../common/index.js'; -import { EWorkerType, IWorkerRunnable } from './types/index.js'; +import { + EWorkerThreadParentMessage, + EWorkerType, + IWorkerRunnable, +} from './types/index.js'; import { PowerSwitch } from '../power-switch/power-switch.js'; import { WorkerAlreadyDownError, @@ -16,38 +20,32 @@ import { } from './errors/index.js'; import { Worker } from './worker.js'; -export class WorkerRunnable - extends Worker - implements IWorkerRunnable +export class WorkerRunnable + extends Worker + implements IWorkerRunnable { protected readonly type: EWorkerType = EWorkerType.RUNNABLE; protected readonly powerSwitch; - constructor(workerFilename: string) { - super(workerFilename); + constructor(workerFilename: string, initialPayload?: InitialPayload) { + super(workerFilename, initialPayload); this.powerSwitch = new PowerSwitch(); } - run(initialPayload: Payload, cb: ICallback) { + run(cb: ICallback) { const r = this.powerSwitch.goingUp(); if (r) { - this.exec(initialPayload, (err) => { - if (err) { - this.powerSwitch.rollback(); - cb(err); - } else { - this.powerSwitch.commit(); - this.registerEvents(this); - cb(); - } - }); + this.registerEvents(this); + this.postMessage({ type: EWorkerThreadParentMessage.RUN }); + this.powerSwitch.commit(); + cb(); } else cb(new WorkerAlreadyRunningError()); } - override shutDown(cb: ICallback) { + override shutdown(cb: ICallback) { const r = this.powerSwitch.goingDown(); if (r) { - super.shutDown(() => { + super.shutdown(() => { this.powerSwitch.commit(); cb(); }); diff --git a/src/worker/worker-thread.ts b/src/worker/worker-thread.ts deleted file mode 100644 index 54d1722..0000000 --- a/src/worker/worker-thread.ts +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) - * Weyoss - * https://github.com/weyoss - * - * This source code is licensed under the MIT license found in the LICENSE file - * in the root directory of this source tree. - */ - -import { statSync } from 'fs'; -import { extname } from 'path'; -import { - isMainThread, - MessagePort, - parentPort, - // type-coverage:ignore-next-line - workerData, -} from 'worker_threads'; -import { - EWorkerThreadExecutionCode, - EWorkerThreadExitCode, - EWorkerType, - IWorkerData, - TWorkerFn, - TWorkerThreadMessage, - TWorkerThreadMessageCode, -} from './types/index.js'; - -function importWorkerFn( - filename: string, - cb: (worker: TWorkerFn) => void, -): void { - import(filename) - .then((importedModule: { default?: TWorkerFn } | TWorkerFn) => { - const fn = - typeof importedModule !== 'function' && importedModule.default - ? importedModule.default - : importedModule; - if (typeof fn !== 'function') { - exit(EWorkerThreadExitCode.INVALID_WORKER_TYPE); - } else cb(fn); - }) - .catch(() => { - exit(EWorkerThreadExitCode.FILE_IMPORT_ERROR); - }); -} - -function formatErrorMessage( - code: TWorkerThreadMessageCode, - err?: unknown, -): TWorkerThreadMessage { - const error = - err && err instanceof Error - ? { name: err.name, message: err.message } - : null; - return { - code, - error, - }; -} - -function formatOKMessage(data: unknown): TWorkerThreadMessage { - return { - code: EWorkerThreadExecutionCode.OK, - data, - }; -} - -function postMessage( - messagePort: MessagePort, - code: TWorkerThreadMessageCode, - err?: unknown, - data?: unknown, -) { - const msg = - code === EWorkerThreadExecutionCode.OK - ? formatOKMessage(data) - : formatErrorMessage(code, err); - messagePort.postMessage(msg); -} - -function exit(code: TWorkerThreadMessageCode, err?: unknown) { - parentPort && postMessage(parentPort, code, err); - process.exit(code); -} - -if (!isMainThread && parentPort) { - // type-coverage:ignore-next-line - if (!workerData) { - exit(EWorkerThreadExitCode.WORKER_DATA_REQUIRED); - } else { - const messagePort: MessagePort = parentPort; - - const { type, filename }: IWorkerData = workerData; - - if (!['.js', '.cjs'].includes(extname(filename))) { - exit(EWorkerThreadExitCode.FILE_EXTENSION_ERROR); - } - - try { - statSync(filename); - } catch (e: unknown) { - exit(EWorkerThreadExitCode.FILE_READ_ERROR, e); - } - - importWorkerFn(filename, (workerFn) => { - const callback = (err?: Error | null, reply?: unknown) => { - if (err) { - postMessage( - messagePort, - EWorkerThreadExecutionCode.PROCESSING_ERROR, - err, - ); - } else { - postMessage(messagePort, EWorkerThreadExecutionCode.OK, null, reply); - } - }; - - const onMessage = (...args: unknown[]) => { - try { - workerFn(...args, callback); - } catch (err: unknown) { - postMessage( - messagePort, - EWorkerThreadExecutionCode.PROCESSING_CAUGHT_ERROR, - err, - ); - } - }; - if (type === EWorkerType.CALLABLE) messagePort.on('message', onMessage); - else messagePort.once('message', onMessage); - }); - } - - process.on('uncaughtException', (err) => { - exit(EWorkerThreadExitCode.UNCAUGHT_EXCEPTION, err); - }); -} diff --git a/src/worker/worker-thread/worker-thread-callable.ts b/src/worker/worker-thread/worker-thread-callable.ts new file mode 100644 index 0000000..27f4442 --- /dev/null +++ b/src/worker/worker-thread/worker-thread-callable.ts @@ -0,0 +1,49 @@ +/* + * Copyright (c) + * Weyoss + * https://github.com/weyoss + * + * This source code is licensed under the MIT license found in the LICENSE file + * in the root directory of this source tree. + */ + +import { MessagePort } from 'worker_threads'; +import { + EWorkerThreadChildExecutionCode, + EWorkerThreadParentMessage, + TWorkerCallableFunction, + TWorkerThreadParentMessage, +} from '../types/index.js'; +import { postMessage } from './worker-thread-message.js'; + +export function handleWorkerCallable( + worker: TWorkerCallableFunction, + messagePort: MessagePort, +) { + const callback = (err?: Error | null, reply?: unknown) => { + if (err) { + postMessage( + messagePort, + EWorkerThreadChildExecutionCode.PROCESSING_ERROR, + err, + ); + } else { + postMessage(messagePort, EWorkerThreadChildExecutionCode.OK, null, reply); + } + }; + const onMessage = (message: TWorkerThreadParentMessage) => { + if (message.type === EWorkerThreadParentMessage.CALL) { + const { payload } = message; + try { + worker(payload, callback); + } catch (err: unknown) { + postMessage( + messagePort, + EWorkerThreadChildExecutionCode.PROCESSING_CAUGHT_ERROR, + err, + ); + } + } + }; + messagePort.on('message', onMessage); +} diff --git a/src/worker/worker-thread/worker-thread-message.ts b/src/worker/worker-thread/worker-thread-message.ts new file mode 100644 index 0000000..a34040d --- /dev/null +++ b/src/worker/worker-thread/worker-thread-message.ts @@ -0,0 +1,53 @@ +/* + * Copyright (c) + * Weyoss + * https://github.com/weyoss + * + * This source code is licensed under the MIT license found in the LICENSE file + * in the root directory of this source tree. + */ +import { MessagePort, parentPort } from 'worker_threads'; +import { + EWorkerThreadChildExecutionCode, + TWorkerThreadChildMessage, + TWorkerThreadChildMessageCode, +} from '../types/worker-thread.js'; + +function formatErrorMessage( + code: TWorkerThreadChildMessageCode, + err?: unknown, +): TWorkerThreadChildMessage { + const error = + err && err instanceof Error + ? { name: err.name, message: err.message } + : null; + return { + code, + error, + }; +} + +function formatOKMessage(data?: unknown): TWorkerThreadChildMessage { + return { + code: EWorkerThreadChildExecutionCode.OK, + data, + }; +} + +export function postMessage( + messagePort: MessagePort, + code: TWorkerThreadChildMessageCode, + err?: unknown, + data?: unknown, +) { + const msg = + code === EWorkerThreadChildExecutionCode.OK + ? formatOKMessage(data) + : formatErrorMessage(code, err); + messagePort.postMessage(msg); +} + +export function exit(code: TWorkerThreadChildMessageCode, err?: unknown) { + parentPort && postMessage(parentPort, code, err); + process.exit(code); +} diff --git a/src/worker/worker-thread/worker-thread-runnable.ts b/src/worker/worker-thread/worker-thread-runnable.ts new file mode 100644 index 0000000..c766dee --- /dev/null +++ b/src/worker/worker-thread/worker-thread-runnable.ts @@ -0,0 +1,58 @@ +/* + * Copyright (c) + * Weyoss + * https://github.com/weyoss + * + * This source code is licensed under the MIT license found in the LICENSE file + * in the root directory of this source tree. + */ + +import { MessagePort } from 'worker_threads'; +import { + EWorkerThreadChildExecutionCode, + EWorkerThreadChildExitCode, + EWorkerThreadParentMessage, + IWorkerRunnable, + TWorkerThreadParentMessage, + TWorkerRunnableFunctionFactory, +} from '../types/index.js'; +import { exit } from './worker-thread-message.js'; + +export function handleWorkerRunnable( + worker: TWorkerRunnableFunctionFactory, + messagePort: MessagePort, + initialPayload: unknown, +) { + let instance: IWorkerRunnable | null = null; + try { + instance = worker(initialPayload); + } catch (err: unknown) { + exit(EWorkerThreadChildExitCode.INVALID_WORKER_TYPE, err); + } + if ( + !instance || + typeof instance !== 'object' || + !instance?.run || + !instance?.shutdown + ) { + exit(EWorkerThreadChildExitCode.INVALID_WORKER_TYPE); + } else { + const run = () => { + try { + instance?.run((err?: unknown | null) => { + if (err) exit(EWorkerThreadChildExecutionCode.PROCESSING_ERROR, err); + }); + } catch (err: unknown) { + exit(EWorkerThreadChildExecutionCode.PROCESSING_CAUGHT_ERROR, err); + } + }; + const shutdown = () => { + instance?.shutdown(() => void 0); + }; + const onMessage = (message: TWorkerThreadParentMessage) => { + if (message.type === EWorkerThreadParentMessage.RUN) run(); + if (message.type === EWorkerThreadParentMessage.SHUTDOWN) shutdown(); + }; + messagePort.on('message', onMessage); + } +} diff --git a/src/worker/worker-thread/worker-thread.ts b/src/worker/worker-thread/worker-thread.ts new file mode 100644 index 0000000..e7021b6 --- /dev/null +++ b/src/worker/worker-thread/worker-thread.ts @@ -0,0 +1,80 @@ +/* + * Copyright (c) + * Weyoss + * https://github.com/weyoss + * + * This source code is licensed under the MIT license found in the LICENSE file + * in the root directory of this source tree. + */ + +import { statSync } from 'fs'; +import { extname } from 'path'; +import { + isMainThread, + MessagePort, + parentPort, + // type-coverage:ignore-next-line + workerData, +} from 'worker_threads'; +import { + EWorkerThreadChildExitCode, + EWorkerType, + IWorkerThreadData, + TWorkerFunction, + TWorkerRunnableFunctionFactory, +} from '../types/index.js'; +import { handleWorkerCallable } from './worker-thread-callable.js'; +import { exit } from './worker-thread-message.js'; +import { handleWorkerRunnable } from './worker-thread-runnable.js'; + +function importWorkerInstance( + filename: string, + cb: (worker: TWorkerFunction) => void, +): void { + if (!['.js', '.cjs'].includes(extname(filename))) { + exit(EWorkerThreadChildExitCode.FILE_EXTENSION_ERROR); + } + try { + statSync(filename); + } catch (e: unknown) { + exit(EWorkerThreadChildExitCode.FILE_READ_ERROR, e); + } + import(filename) + .then((importedModule: { default?: TWorkerFunction } | TWorkerFunction) => { + const fn = + typeof importedModule !== 'function' && importedModule.default + ? importedModule.default + : importedModule; + if (typeof fn !== 'function') { + exit(EWorkerThreadChildExitCode.INVALID_WORKER_TYPE); + } else cb(fn); + }) + .catch(() => { + exit(EWorkerThreadChildExitCode.FILE_IMPORT_ERROR); + }); +} + +function isRunnableFunctionFactory( + worker: TWorkerFunction, + type: EWorkerType, +): worker is TWorkerRunnableFunctionFactory { + return type === EWorkerType.RUNNABLE; +} + +if (!isMainThread && parentPort) { + // type-coverage:ignore-next-line + if (!workerData) { + exit(EWorkerThreadChildExitCode.WORKER_DATA_REQUIRED); + } else { + const messagePort: MessagePort = parentPort; + const { filename, initialPayload, type }: IWorkerThreadData = workerData; + importWorkerInstance(filename, (worker) => { + if (isRunnableFunctionFactory(worker, type)) + handleWorkerRunnable(worker, messagePort, initialPayload); + else handleWorkerCallable(worker, messagePort); + }); + } + process.on('uncaughtException', (err) => { + exit(EWorkerThreadChildExitCode.UNCAUGHT_EXCEPTION, err); + }); +} diff --git a/src/worker/worker.ts b/src/worker/worker.ts index 4f764fe..625b46f 100644 --- a/src/worker/worker.ts +++ b/src/worker/worker.ts @@ -11,10 +11,11 @@ import { resolve } from 'path'; import { Worker as WorkerThread } from 'worker_threads'; import { ICallback } from '../common/index.js'; import { - EWorkerThreadExecutionCode, - EWorkerThreadExitCode, + EWorkerThreadChildExecutionCode, + EWorkerThreadChildExitCode, EWorkerType, - TWorkerThreadMessage, + TWorkerThreadChildMessage, + TWorkerThreadParentMessage, } from './types/index.js'; import { getDirname } from '../env/environment.js'; import { EventEmitter } from '../event/index.js'; @@ -27,21 +28,33 @@ export type TWorkerEvent = { const dir = getDirname(); -export abstract class Worker extends EventEmitter { +export abstract class Worker< + Payload, + Reply, +> extends EventEmitter { protected abstract readonly type: EWorkerType; protected readonly workerFilename; + protected readonly initialPayload; protected workerThread: WorkerThread | null = null; - constructor(workerFilename: string) { + constructor(workerFilename: string, initialPayload?: unknown) { super(); this.workerFilename = workerFilename; + this.initialPayload = initialPayload; } protected getWorkerThread(): WorkerThread { if (!this.workerThread) { - this.workerThread = new WorkerThread(resolve(dir, './worker-thread.js'), { - workerData: { filename: this.workerFilename, type: this.type }, - }); + this.workerThread = new WorkerThread( + resolve(dir, './worker-thread/worker-thread.js'), + { + workerData: { + filename: this.workerFilename, + initialPayload: this.initialPayload, + type: this.type, + }, + }, + ); this.workerThread.on('messageerror', (err) => { console.error(err); }); @@ -55,14 +68,16 @@ export abstract class Worker extends EventEmitter { return this.workerThread; } - protected registerEvents(cb: ICallback | Worker): void { + protected registerEvents( + cb: ICallback | Worker, + ): void { const worker = this.getWorkerThread(); const cleanUp = () => { worker .removeListener('message', onMessage) .removeListener('exit', onExit); }; - const callback: ICallback = (err, data) => { + const callback: ICallback = (err, data) => { if (err) { if (cb instanceof Worker) { this.emit('worker.error', err); @@ -72,16 +87,16 @@ export abstract class Worker extends EventEmitter { else cb(null, data); } }; - const onMessage = (msg: TWorkerThreadMessage) => { + const onMessage = (msg: TWorkerThreadChildMessage) => { cleanUp(); - if (msg.code !== EWorkerThreadExecutionCode.OK) { + if (msg.code !== EWorkerThreadChildExecutionCode.OK) { callback(new WorkerThreadError(msg)); } else callback(null, msg.data); }; const onExit = () => { cleanUp(); const msg = { - code: EWorkerThreadExitCode.TERMINATED, + code: EWorkerThreadChildExitCode.TERMINATED, error: null, }; callback(new WorkerThreadError(msg)); @@ -90,13 +105,11 @@ export abstract class Worker extends EventEmitter { worker.once('exit', onExit); } - protected exec(payload: unknown, cb: ICallback): void { - this.registerEvents(cb); - if (!(payload === null || payload === undefined)) - this.getWorkerThread().postMessage(payload); + postMessage(message: TWorkerThreadParentMessage): void { + this.getWorkerThread().postMessage(message); } - shutDown(cb: ICallback) { + shutdown(cb: ICallback) { const callback = () => { this.workerThread = null; cb(); diff --git a/tests/event/test00001.test.ts b/tests/event/test00001.test.ts index 3aa6749..7f989dc 100644 --- a/tests/event/test00001.test.ts +++ b/tests/event/test00001.test.ts @@ -67,7 +67,7 @@ it('EventBus: case 1', async () => { eventBusAsync.emit('e1', 'hello7'); expect(callback5).toHaveBeenCalledTimes(1); - await eventBusAsync.shutDownAsync(); + await eventBusAsync.shutdownAsync(); const errors: Error[] = []; eventBusAsync.once('error', (e) => errors.push(e)); diff --git a/tests/event/test00002.test.ts b/tests/event/test00002.test.ts index 2ec4d9c..e02fa91 100644 --- a/tests/event/test00002.test.ts +++ b/tests/event/test00002.test.ts @@ -78,10 +78,10 @@ it('EventBusRedis: case 1', async () => { eventBusAsync.emit('e1', 'hello7'); expect(callback5).toHaveBeenCalledTimes(1); - await eventBusAsync.shutDownAsync(); + await eventBusAsync.shutdownAsync(); // second time - await eventBusAsync.shutDownAsync(); + await eventBusAsync.shutdownAsync(); const errors: Error[] = []; eventBusAsync.once('error', (e) => errors.push(e)); diff --git a/tests/redis-client/common.ts b/tests/redis-client/common.ts index 0ec6bb1..e603e8a 100644 --- a/tests/redis-client/common.ts +++ b/tests/redis-client/common.ts @@ -184,8 +184,8 @@ export async function standardCommands(config: IRedisConfig) { ); } - await client.shutDownAsync(); // does exec quit command - await client.shutDownAsync(); // does not exec quit + await client.shutdownAsync(); // does exec quit command + await client.shutdownAsync(); // does not exec quit } export async function scriptRunning(config: IRedisConfig) { diff --git a/tests/worker/test00001.test.ts b/tests/worker/test00001.test.ts index 23f5f31..be7955f 100644 --- a/tests/worker/test00001.test.ts +++ b/tests/worker/test00001.test.ts @@ -28,8 +28,8 @@ it('WorkerCallable: case 1', async () => { WorkerPayloadRequiredError, ); - await worker.shutDownAsync(); + await worker.shutdownAsync(); // second timer is OK - await worker.shutDownAsync(); + await worker.shutdownAsync(); }); diff --git a/tests/worker/test00002.test.ts b/tests/worker/test00002.test.ts index 52c6b6b..b3c9530 100644 --- a/tests/worker/test00002.test.ts +++ b/tests/worker/test00002.test.ts @@ -46,7 +46,7 @@ it('WorkerCallable: case 2', async () => { await expect(worker3.callAsync('Hello world!')).rejects.toThrow( 'Error code: PROCESSING_ERROR', ); - await worker3.shutDownAsync(); + await worker3.shutdownAsync(); const filename4 = resolve(dir, './workers/worker-exception.worker.js'); const worker4 = bluebird.promisifyAll( @@ -55,7 +55,7 @@ it('WorkerCallable: case 2', async () => { await expect(worker4.callAsync('Hello world!')).rejects.toThrow( 'Error code: PROCESSING_CAUGHT_ERROR', ); - await worker4.shutDownAsync(); + await worker4.shutdownAsync(); const filename5 = resolve(dir, './workers/worker-faulty.worker.js'); const worker5 = bluebird.promisifyAll( diff --git a/tests/worker/test00003.test.ts b/tests/worker/test00003.test.ts index 7859fd8..fd206f9 100644 --- a/tests/worker/test00003.test.ts +++ b/tests/worker/test00003.test.ts @@ -13,8 +13,10 @@ import { EventEmitter } from 'events'; import { resolve } from 'node:path'; import { getDirname } from '../../src/env/environment.js'; import { - EWorkerThreadExecutionCode, + EWorkerThreadChildExecutionCode, + EWorkerThreadParentMessage, EWorkerType, + TWorkerThreadParentMessage, } from '../../src/worker/index.js'; import { mockModule } from '../mock-module.js'; @@ -40,18 +42,22 @@ it('WorkerCallable: case 3', async () => { // @ts-ignore const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {}); // type-coverage:ignore-line - await import('../../src/worker/worker-thread.js'); + await import('../../src/worker/worker-thread/worker-thread.js'); await bluebird.delay(5000); - mockParentPort.emit('message', '123456789'); + const message: TWorkerThreadParentMessage = { + type: EWorkerThreadParentMessage.CALL, + payload: '123456', + }; + mockParentPort.emit('message', message); await bluebird.delay(5000); expect(mockParentPort.postMessage).toHaveBeenCalledTimes(1); expect(mockParentPort.postMessage).toHaveBeenCalledWith({ - code: EWorkerThreadExecutionCode.OK, - data: '123456789', + code: EWorkerThreadChildExecutionCode.OK, + data: message.payload, }); expect(mockExit).toHaveBeenCalledTimes(0); // type-coverage:ignore-line diff --git a/tests/worker/test00004.test.ts b/tests/worker/test00004.test.ts index 98d78fe..a307dcf 100644 --- a/tests/worker/test00004.test.ts +++ b/tests/worker/test00004.test.ts @@ -13,7 +13,8 @@ import { EventEmitter } from 'events'; import { resolve } from 'node:path'; import { getDirname } from '../../src/env/environment.js'; import { - EWorkerThreadExecutionCode, + EWorkerThreadChildExecutionCode, + EWorkerThreadParentMessage, EWorkerType, } from '../../src/worker/index.js'; import { mockModule } from '../mock-module.js'; @@ -40,17 +41,20 @@ it('WorkerCallable: case 4', async () => { // @ts-ignore const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {}); // type-coverage:ignore-line - await import('../../src/worker/worker-thread.js'); + await import('../../src/worker/worker-thread/worker-thread.js'); await bluebird.delay(5000); - mockParentPort.emit('message', '123456789'); + mockParentPort.emit('message', { + type: EWorkerThreadParentMessage.CALL, + payload: '123456', + }); await bluebird.delay(5000); expect(mockParentPort.postMessage).toHaveBeenCalledTimes(1); expect(mockParentPort.postMessage).toHaveBeenCalledWith({ - code: EWorkerThreadExecutionCode.PROCESSING_ERROR, + code: EWorkerThreadChildExecutionCode.PROCESSING_ERROR, error: { name: 'Error', message: 'MY_ERROR' }, }); diff --git a/tests/worker/test00005.test.ts b/tests/worker/test00005.test.ts index f02110e..b44fed4 100644 --- a/tests/worker/test00005.test.ts +++ b/tests/worker/test00005.test.ts @@ -13,7 +13,8 @@ import { EventEmitter } from 'events'; import { resolve } from 'node:path'; import { getDirname } from '../../src/env/environment.js'; import { - EWorkerThreadExecutionCode, + EWorkerThreadChildExecutionCode, + EWorkerThreadParentMessage, EWorkerType, } from '../../src/worker/index.js'; import { mockModule } from '../mock-module.js'; @@ -40,17 +41,20 @@ it('WorkerCallable: case 5', async () => { // @ts-ignore const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {}); // type-coverage:ignore-line - await import('../../src/worker/worker-thread.js'); + await import('../../src/worker/worker-thread/worker-thread.js'); await bluebird.delay(5000); - mockParentPort.emit('message', '123456789'); + mockParentPort.emit('message', { + type: EWorkerThreadParentMessage.CALL, + payload: '123456', + }); await bluebird.delay(5000); expect(mockParentPort.postMessage).toHaveBeenCalledTimes(1); expect(mockParentPort.postMessage).toHaveBeenCalledWith({ - code: EWorkerThreadExecutionCode.PROCESSING_CAUGHT_ERROR, + code: EWorkerThreadChildExecutionCode.PROCESSING_CAUGHT_ERROR, error: { name: 'Error', message: 'THROW_ERROR' }, }); diff --git a/tests/worker/test00006.test.ts b/tests/worker/test00006.test.ts index af98fe1..b124d1a 100644 --- a/tests/worker/test00006.test.ts +++ b/tests/worker/test00006.test.ts @@ -12,7 +12,11 @@ import bluebird from 'bluebird'; import { EventEmitter } from 'events'; import { resolve } from 'node:path'; import { getDirname } from '../../src/env/environment.js'; -import { EWorkerThreadExitCode, EWorkerType } from '../../src/worker/index.js'; +import { + EWorkerThreadChildExitCode, + EWorkerThreadParentMessage, + EWorkerType, +} from '../../src/worker/index.js'; import { mockModule } from '../mock-module.js'; const dir = getDirname(); @@ -37,17 +41,20 @@ it('WorkerCallable: case 6', async () => { // @ts-ignore const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {}); // type-coverage:ignore-line - await import('../../src/worker/worker-thread.js'); + await import('../../src/worker/worker-thread/worker-thread.js'); await bluebird.delay(5000); - mockParentPort.emit('message', '123456789'); + mockParentPort.emit('message', { + type: EWorkerThreadParentMessage.CALL, + payload: '123456', + }); await bluebird.delay(5000); expect(mockParentPort.postMessage).toHaveBeenCalledTimes(1); expect(mockParentPort.postMessage).toHaveBeenCalledWith({ - code: EWorkerThreadExitCode.INVALID_WORKER_TYPE, + code: EWorkerThreadChildExitCode.INVALID_WORKER_TYPE, error: null, }); @@ -56,6 +63,6 @@ it('WorkerCallable: case 6', async () => { // type-coverage:ignore-next-line expect(mockExit).toHaveBeenCalledWith( - EWorkerThreadExitCode.INVALID_WORKER_TYPE, + EWorkerThreadChildExitCode.INVALID_WORKER_TYPE, ); }); diff --git a/tests/worker/test00007.test.ts b/tests/worker/test00007.test.ts index 51180c8..7c8f8e9 100644 --- a/tests/worker/test00007.test.ts +++ b/tests/worker/test00007.test.ts @@ -12,7 +12,11 @@ import bluebird from 'bluebird'; import { EventEmitter } from 'events'; import { resolve } from 'node:path'; import { getDirname } from '../../src/env/environment.js'; -import { EWorkerThreadExitCode, EWorkerType } from '../../src/worker/index.js'; +import { + EWorkerThreadChildExitCode, + EWorkerThreadParentMessage, + EWorkerType, +} from '../../src/worker/index.js'; import { mockModule } from '../mock-module.js'; const dir = getDirname(); @@ -37,11 +41,14 @@ it('WorkerCallable: case 7', async () => { // @ts-ignore const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {}); // type-coverage:ignore-line - await import('../../src/worker/worker-thread.js'); + await import('../../src/worker/worker-thread/worker-thread.js'); await bluebird.delay(5000); - mockParentPort.emit('message', '123456789'); + mockParentPort.emit('message', { + type: EWorkerThreadParentMessage.CALL, + payload: '123456', + }); await bluebird.delay(5000); @@ -58,6 +65,6 @@ it('WorkerCallable: case 7', async () => { // type-coverage:ignore-next-line expect(mockExit).toHaveBeenNthCalledWith( 2, - EWorkerThreadExitCode.INVALID_WORKER_TYPE, + EWorkerThreadChildExitCode.INVALID_WORKER_TYPE, ); }); diff --git a/tests/worker/test00008.test.ts b/tests/worker/test00008.test.ts index 091b901..1aa5b0d 100644 --- a/tests/worker/test00008.test.ts +++ b/tests/worker/test00008.test.ts @@ -10,7 +10,10 @@ import { expect, it, jest } from '@jest/globals'; import bluebird from 'bluebird'; import { EventEmitter } from 'events'; -import { EWorkerThreadExitCode } from '../../src/worker/index.js'; +import { + EWorkerThreadChildExitCode, + EWorkerThreadParentMessage, +} from '../../src/worker/index.js'; import { mockModule } from '../mock-module.js'; it('WorkerCallable: case 8', async () => { @@ -30,11 +33,14 @@ it('WorkerCallable: case 8', async () => { // @ts-ignore const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {}); // type-coverage:ignore-line - await import('../../src/worker/worker-thread.js'); + await import('../../src/worker/worker-thread/worker-thread.js'); await bluebird.delay(5000); - mockParentPort.emit('message', '123456789'); + mockParentPort.emit('message', { + type: EWorkerThreadParentMessage.CALL, + payload: '123456', + }); await bluebird.delay(5000); @@ -42,7 +48,7 @@ it('WorkerCallable: case 8', async () => { // But process.exit is mocked so getHandlerFn() is called with empty workerData expect(mockParentPort.postMessage).toHaveBeenCalledTimes(1); expect(mockParentPort.postMessage).toHaveBeenNthCalledWith(1, { - code: EWorkerThreadExitCode.WORKER_DATA_REQUIRED, + code: EWorkerThreadChildExitCode.WORKER_DATA_REQUIRED, error: null, }); @@ -55,6 +61,6 @@ it('WorkerCallable: case 8', async () => { // type-coverage:ignore-next-line expect(mockExit).toHaveBeenNthCalledWith( 1, - EWorkerThreadExitCode.WORKER_DATA_REQUIRED, + EWorkerThreadChildExitCode.WORKER_DATA_REQUIRED, ); }); diff --git a/tests/worker/test00009.test.ts b/tests/worker/test00009.test.ts index 2a095e1..fe08447 100644 --- a/tests/worker/test00009.test.ts +++ b/tests/worker/test00009.test.ts @@ -12,7 +12,11 @@ import bluebird from 'bluebird'; import { EventEmitter } from 'events'; import { resolve } from 'node:path'; import { getDirname } from '../../src/env/environment.js'; -import { EWorkerThreadExitCode, EWorkerType } from '../../src/worker/index.js'; +import { + EWorkerThreadChildExitCode, + EWorkerThreadParentMessage, + EWorkerType, +} from '../../src/worker/index.js'; import { mockModule } from '../mock-module.js'; const dir = getDirname(); @@ -37,11 +41,14 @@ it('WorkerCallable: case 9', async () => { // @ts-ignore const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {}); // type-coverage:ignore-line - await import('../../src/worker/worker-thread.js'); + await import('../../src/worker/worker-thread/worker-thread.js'); await bluebird.delay(5000); - mockParentPort.emit('message', '123456789'); + mockParentPort.emit('message', { + type: EWorkerThreadParentMessage.CALL, + payload: '123456', + }); await bluebird.delay(5000); @@ -54,12 +61,12 @@ it('WorkerCallable: case 9', async () => { // type-coverage:ignore-next-line expect(mockExit).toHaveBeenNthCalledWith( 1, - EWorkerThreadExitCode.FILE_READ_ERROR, + EWorkerThreadChildExitCode.FILE_READ_ERROR, ); // type-coverage:ignore-next-line expect(mockExit).toHaveBeenNthCalledWith( 2, - EWorkerThreadExitCode.FILE_IMPORT_ERROR, + EWorkerThreadChildExitCode.FILE_IMPORT_ERROR, ); }); diff --git a/tests/worker/test00010.test.ts b/tests/worker/test00010.test.ts index 7b71a4e..9af655c 100644 --- a/tests/worker/test00010.test.ts +++ b/tests/worker/test00010.test.ts @@ -12,7 +12,11 @@ import bluebird from 'bluebird'; import { EventEmitter } from 'events'; import { resolve } from 'node:path'; import { getDirname } from '../../src/env/environment.js'; -import { EWorkerThreadExitCode, EWorkerType } from '../../src/worker/index.js'; +import { + EWorkerThreadChildExitCode, + EWorkerThreadParentMessage, + EWorkerType, +} from '../../src/worker/index.js'; import { mockModule } from '../mock-module.js'; const dir = getDirname(); @@ -37,11 +41,14 @@ it('WorkerCallable: case 10', async () => { // @ts-ignore const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {}); // type-coverage:ignore-line - await import('../../src/worker/worker-thread.js'); + await import('../../src/worker/worker-thread/worker-thread.js'); await bluebird.delay(5000); - mockParentPort.emit('message', '123456789'); + mockParentPort.emit('message', { + type: EWorkerThreadParentMessage.CALL, + payload: '123456', + }); await bluebird.delay(5000); @@ -54,18 +61,18 @@ it('WorkerCallable: case 10', async () => { // type-coverage:ignore-next-line expect(mockExit).toHaveBeenNthCalledWith( 1, - EWorkerThreadExitCode.FILE_EXTENSION_ERROR, + EWorkerThreadChildExitCode.FILE_EXTENSION_ERROR, ); // type-coverage:ignore-next-line expect(mockExit).toHaveBeenNthCalledWith( 2, - EWorkerThreadExitCode.FILE_READ_ERROR, + EWorkerThreadChildExitCode.FILE_READ_ERROR, ); // type-coverage:ignore-next-line expect(mockExit).toHaveBeenNthCalledWith( 3, - EWorkerThreadExitCode.FILE_IMPORT_ERROR, + EWorkerThreadChildExitCode.FILE_IMPORT_ERROR, ); }); diff --git a/tests/worker/test00011.test.ts b/tests/worker/test00011.test.ts index 03d4db3..36b2abe 100644 --- a/tests/worker/test00011.test.ts +++ b/tests/worker/test00011.test.ts @@ -26,15 +26,15 @@ it('WorkerRunnable', async () => { worker.on('worker.error', (err) => { console.error(err); }); - await worker.runAsync('Hello world!'); + await worker.runAsync(); - await expect(async () => worker.runAsync('Hello world!')).rejects.toThrow( + await expect(async () => worker.runAsync()).rejects.toThrow( WorkerAlreadyRunningError, ); - await worker.shutDownAsync(); + await worker.shutdownAsync(); - await expect(async () => worker.shutDownAsync()).rejects.toThrow( + await expect(async () => worker.shutdownAsync()).rejects.toThrow( WorkerAlreadyDownError, ); }); diff --git a/tests/worker/test00013.test.ts b/tests/worker/test00013.test.ts index 8991cc2..4b172f9 100644 --- a/tests/worker/test00013.test.ts +++ b/tests/worker/test00013.test.ts @@ -28,8 +28,6 @@ it('WorkerResourceGroup: loadFromDir()', async () => { 'hello world', ); await workerRunnableResourceGroup.runAsync(); - await bluebird.delay(10000); - await workerRunnableResourceGroup.shutdownAsync(); }); diff --git a/tests/worker/workers/runnable/runnable1.worker.ts b/tests/worker/workers/runnable/runnable1.worker.ts index 7b673ba..0848d10 100644 --- a/tests/worker/workers/runnable/runnable1.worker.ts +++ b/tests/worker/workers/runnable/runnable1.worker.ts @@ -8,8 +8,18 @@ */ import { ICallback } from '../../../../src/common/index.js'; +import { IWorkerRunnable } from '../../../../src/worker/types/worker.js'; -export default function myWorkerRunnable(msg: string, cb: ICallback) { - setInterval(() => void 0, 1000); - cb(); +export default function myWorkerRunnable(): IWorkerRunnable { + let interval: NodeJS.Timeout | null = null; + return { + run(cb: ICallback) { + interval = setInterval(() => void 0, 1000); + cb(); + }, + shutdown(cb: ICallback) { + if (interval) clearInterval(interval); + cb(); + }, + }; } diff --git a/tests/worker/workers/runnable/runnable2.worker.ts b/tests/worker/workers/runnable/runnable2.worker.ts index 7b673ba..0848d10 100644 --- a/tests/worker/workers/runnable/runnable2.worker.ts +++ b/tests/worker/workers/runnable/runnable2.worker.ts @@ -8,8 +8,18 @@ */ import { ICallback } from '../../../../src/common/index.js'; +import { IWorkerRunnable } from '../../../../src/worker/types/worker.js'; -export default function myWorkerRunnable(msg: string, cb: ICallback) { - setInterval(() => void 0, 1000); - cb(); +export default function myWorkerRunnable(): IWorkerRunnable { + let interval: NodeJS.Timeout | null = null; + return { + run(cb: ICallback) { + interval = setInterval(() => void 0, 1000); + cb(); + }, + shutdown(cb: ICallback) { + if (interval) clearInterval(interval); + cb(); + }, + }; } diff --git a/tests/worker/workers/worker-error.worker.ts b/tests/worker/workers/worker-error.worker.ts index f20b867..c1efaed 100644 --- a/tests/worker/workers/worker-error.worker.ts +++ b/tests/worker/workers/worker-error.worker.ts @@ -7,7 +7,7 @@ * in the root directory of this source tree. */ -import { ICallback } from '../../../src/common/index.js'; +import { ICallback } from '../../../src/common/types/index.js'; export default function myWorkerCallable(msg: string, cb: ICallback) { cb(new Error('MY_ERROR')); diff --git a/tests/worker/workers/worker-ok.worker.ts b/tests/worker/workers/worker-ok.worker.ts index ecea1cd..513f9ff 100644 --- a/tests/worker/workers/worker-ok.worker.ts +++ b/tests/worker/workers/worker-ok.worker.ts @@ -7,11 +7,8 @@ * in the root directory of this source tree. */ -import { ICallback } from '../../../src/common/index.js'; +import { ICallback } from '../../../src/common/types/index.js'; -export default function myWorkerCallable( - payload: string, - cb: ICallback, -) { - setTimeout(() => cb(null, payload), 5000); +export default function myWorkerCallable(args: string, cb: ICallback) { + setTimeout(() => cb(null, args), 5000); }