From 242b28ce291cd255a974da6ff0ecc04b84db04bb Mon Sep 17 00:00:00 2001 From: Brian Evans Date: Sat, 23 Sep 2023 21:44:03 +0100 Subject: [PATCH] Use Bun pub/sub in WebSocket server Instead of custom event emitter. Also other cleanup related to the move to Bun Signed-off-by: Brian Evans --- docker-compose.yml | 4 +- server/package.json | 3 +- server/pnpm-lock.yaml | 784 ---------------------------- server/src/redis/streamFromRedis.ts | 66 +-- server/src/redis/streamToRedis.ts | 6 +- server/test/benchmark.ts | 18 + 6 files changed, 51 insertions(+), 830 deletions(-) delete mode 100644 server/pnpm-lock.yaml create mode 100644 server/test/benchmark.ts diff --git a/docker-compose.yml b/docker-compose.yml index 73bfb52..f7d36dd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,7 +31,7 @@ services: event-publisher: build: server - command: bun run stream-pub + command: bun run src/redis/streamToRedis.ts environment: PUBSUB_REDIS_IP: redis env_file: @@ -42,7 +42,7 @@ services: event-subscriber: build: server - command: bun run stream-sub + command: bun run src/redis/streamFromRedis.ts environment: PUBSUB_REDIS_IP: redis logging: diff --git a/server/package.json b/server/package.json index bcc19aa..67b0b60 100644 --- a/server/package.json +++ b/server/package.json @@ -12,12 +12,13 @@ }, "devDependencies": { "@types/node": "^18.11.9", + "bun-types": "^1.0.3", + "mitata": "^0.1.6", "typescript": "^4.8.4" }, "dependencies": { "@streamparser/json-node": "^0.0.15", "JSONStream": "^1.3.5", - "bun-types": "^1.0.3", "elysia": "^0.7.12", "genson-js": "^0.0.8", "pino": "^8.7.0", diff --git a/server/pnpm-lock.yaml b/server/pnpm-lock.yaml deleted file mode 100644 index 2b07b54..0000000 --- a/server/pnpm-lock.yaml +++ /dev/null @@ -1,784 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - '@streamparser/json-node': - specifier: ^0.0.15 - version: 0.0.15 - JSONStream: - specifier: ^1.3.5 - version: 1.3.5 - dotenv: - specifier: ^16.0.3 - version: 16.0.3 - express: - specifier: ^4.18.2 - version: 4.18.2 - genson-js: - specifier: ^0.0.8 - version: 0.0.8 - pino: - specifier: ^8.7.0 - version: 8.7.0 - redis: - specifier: ^4.5.0 - version: 4.5.0 - split2: - specifier: ^4.1.0 - version: 4.1.0 - undici: - specifier: ^5.22.1 - version: 5.22.1 - ws: - specifier: ^8.11.0 - version: 8.11.0 - -devDependencies: - '@types/express': - specifier: ^4.17.14 - version: 4.17.14 - '@types/node': - specifier: ^18.11.9 - version: 18.11.9 - '@types/ws': - specifier: ^8.5.3 - version: 8.5.3 - typescript: - specifier: ^4.8.4 - version: 4.8.4 - -packages: - - /@redis/bloom@1.1.0(@redis/client@1.4.0): - resolution: { integrity: sha512-9QovlxmpRtvxVbN0UBcv8WfdSMudNZZTFqCsnBszcQXqaZb/TVe30ScgGEO7u1EAIacTPAo7/oCYjYAxiHLanQ== } - peerDependencies: - '@redis/client': ^1.0.0 - dependencies: - '@redis/client': 1.4.0 - dev: false - - /@redis/client@1.4.0: - resolution: { integrity: sha512-1gEj1AkyXPlkcC/9/T5xpDcQF8ntERURjLBgEWMTdUZqe181zfI9BY3jc2OzjTLkvZh5GV7VT4ktoJG2fV2ufw== } - engines: { node: '>=14' } - dependencies: - cluster-key-slot: 1.1.1 - generic-pool: 3.9.0 - yallist: 4.0.0 - dev: false - - /@redis/graph@1.1.0(@redis/client@1.4.0): - resolution: { integrity: sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg== } - peerDependencies: - '@redis/client': ^1.0.0 - dependencies: - '@redis/client': 1.4.0 - dev: false - - /@redis/json@1.0.4(@redis/client@1.4.0): - resolution: { integrity: sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw== } - peerDependencies: - '@redis/client': ^1.0.0 - dependencies: - '@redis/client': 1.4.0 - dev: false - - /@redis/search@1.1.0(@redis/client@1.4.0): - resolution: { integrity: sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ== } - peerDependencies: - '@redis/client': ^1.0.0 - dependencies: - '@redis/client': 1.4.0 - dev: false - - /@redis/time-series@1.0.4(@redis/client@1.4.0): - resolution: { integrity: sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng== } - peerDependencies: - '@redis/client': ^1.0.0 - dependencies: - '@redis/client': 1.4.0 - dev: false - - /@streamparser/json-node@0.0.15: - resolution: { integrity: sha512-el3Z9eIXRb2hw2TVFo88tuEgviocSmX4Bz0XCT5teK0lfCVz8odwHRe1oWAzSjpEDqU/2GzIdrCN4jXUuIRJgQ== } - dependencies: - '@streamparser/json': 0.0.15 - dev: false - - /@streamparser/json@0.0.15: - resolution: { integrity: sha512-6oikjkMTYAHGqKmcC9leE4+kY4Ch4eiTImXUN/N4d2bNGBYs0LJ/tfxmpvF5eExSU7iiPlV9jYlADqvj3NWA3Q== } - dev: false - - /@types/body-parser@1.19.2: - resolution: { integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== } - dependencies: - '@types/connect': 3.4.35 - '@types/node': 18.11.9 - dev: true - - /@types/connect@3.4.35: - resolution: { integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== } - dependencies: - '@types/node': 18.11.9 - dev: true - - /@types/express-serve-static-core@4.17.31: - resolution: { integrity: sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q== } - dependencies: - '@types/node': 18.11.9 - '@types/qs': 6.9.7 - '@types/range-parser': 1.2.4 - dev: true - - /@types/express@4.17.14: - resolution: { integrity: sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg== } - dependencies: - '@types/body-parser': 1.19.2 - '@types/express-serve-static-core': 4.17.31 - '@types/qs': 6.9.7 - '@types/serve-static': 1.15.0 - dev: true - - /@types/mime@3.0.1: - resolution: { integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== } - dev: true - - /@types/node@18.11.9: - resolution: { integrity: sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg== } - dev: true - - /@types/qs@6.9.7: - resolution: { integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== } - dev: true - - /@types/range-parser@1.2.4: - resolution: { integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== } - dev: true - - /@types/serve-static@1.15.0: - resolution: { integrity: sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg== } - dependencies: - '@types/mime': 3.0.1 - '@types/node': 18.11.9 - dev: true - - /@types/ws@8.5.3: - resolution: { integrity: sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w== } - dependencies: - '@types/node': 18.11.9 - dev: true - - /JSONStream@1.3.5: - resolution: { integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== } - hasBin: true - dependencies: - jsonparse: 1.3.1 - through: 2.3.8 - dev: false - - /abort-controller@3.0.0: - resolution: { integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== } - engines: { node: '>=6.5' } - dependencies: - event-target-shim: 5.0.1 - dev: false - - /accepts@1.3.8: - resolution: { integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== } - engines: { node: '>= 0.6' } - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - dev: false - - /array-flatten@1.1.1: - resolution: { integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== } - dev: false - - /atomic-sleep@1.0.0: - resolution: { integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== } - engines: { node: '>=8.0.0' } - dev: false - - /base64-js@1.5.1: - resolution: { integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== } - dev: false - - /body-parser@1.20.1: - resolution: { integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== } - engines: { node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16 } - dependencies: - bytes: 3.1.2 - content-type: 1.0.4 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.11.0 - raw-body: 2.5.1 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - dev: false - - /buffer@6.0.3: - resolution: { integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== } - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - dev: false - - /busboy@1.6.0: - resolution: { integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== } - engines: { node: '>=10.16.0' } - dependencies: - streamsearch: 1.1.0 - dev: false - - /bytes@3.1.2: - resolution: { integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== } - engines: { node: '>= 0.8' } - dev: false - - /call-bind@1.0.2: - resolution: { integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== } - dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.1.3 - dev: false - - /cluster-key-slot@1.1.1: - resolution: { integrity: sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw== } - engines: { node: '>=0.10.0' } - dev: false - - /content-disposition@0.5.4: - resolution: { integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== } - engines: { node: '>= 0.6' } - dependencies: - safe-buffer: 5.2.1 - dev: false - - /content-type@1.0.4: - resolution: { integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== } - engines: { node: '>= 0.6' } - dev: false - - /cookie-signature@1.0.6: - resolution: { integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== } - dev: false - - /cookie@0.5.0: - resolution: { integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== } - engines: { node: '>= 0.6' } - dev: false - - /debug@2.6.9: - resolution: { integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== } - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.0.0 - dev: false - - /depd@2.0.0: - resolution: { integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== } - engines: { node: '>= 0.8' } - dev: false - - /destroy@1.2.0: - resolution: { integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== } - engines: { node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16 } - dev: false - - /dotenv@16.0.3: - resolution: { integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ== } - engines: { node: '>=12' } - dev: false - - /ee-first@1.1.1: - resolution: { integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= } - dev: false - - /encodeurl@1.0.2: - resolution: { integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== } - engines: { node: '>= 0.8' } - dev: false - - /escape-html@1.0.3: - resolution: { integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== } - dev: false - - /etag@1.8.1: - resolution: { integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== } - engines: { node: '>= 0.6' } - dev: false - - /event-target-shim@5.0.1: - resolution: { integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== } - engines: { node: '>=6' } - dev: false - - /events@3.3.0: - resolution: { integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== } - engines: { node: '>=0.8.x' } - dev: false - - /express@4.18.2: - resolution: { integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== } - engines: { node: '>= 0.10.0' } - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.1 - content-disposition: 0.5.4 - content-type: 1.0.4 - cookie: 0.5.0 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.2.0 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.1 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.7 - proxy-addr: 2.0.7 - qs: 6.11.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.18.0 - serve-static: 1.15.0 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - dev: false - - /fast-redact@3.1.2: - resolution: { integrity: sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw== } - engines: { node: '>=6' } - dev: false - - /finalhandler@1.2.0: - resolution: { integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== } - engines: { node: '>= 0.8' } - dependencies: - debug: 2.6.9 - encodeurl: 1.0.2 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - dev: false - - /forwarded@0.2.0: - resolution: { integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== } - engines: { node: '>= 0.6' } - dev: false - - /fresh@0.5.2: - resolution: { integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== } - engines: { node: '>= 0.6' } - dev: false - - /function-bind@1.1.1: - resolution: { integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== } - dev: false - - /generic-pool@3.9.0: - resolution: { integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g== } - engines: { node: '>= 4' } - dev: false - - /genson-js@0.0.8: - resolution: { integrity: sha512-4NUusDTwF+lzYh72uKV+Uvpky9iPO+YDIMpGImA5pbHfLV9HwgRCA4hYjGu78V4J4Cx2IZRTFfRERn9aUs74mw== } - dev: false - - /get-intrinsic@1.1.3: - resolution: { integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== } - dependencies: - function-bind: 1.1.1 - has: 1.0.3 - has-symbols: 1.0.3 - dev: false - - /has-symbols@1.0.3: - resolution: { integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== } - engines: { node: '>= 0.4' } - dev: false - - /has@1.0.3: - resolution: { integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== } - engines: { node: '>= 0.4.0' } - dependencies: - function-bind: 1.1.1 - dev: false - - /http-errors@2.0.0: - resolution: { integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== } - engines: { node: '>= 0.8' } - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - dev: false - - /iconv-lite@0.4.24: - resolution: { integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== } - engines: { node: '>=0.10.0' } - dependencies: - safer-buffer: 2.1.2 - dev: false - - /ieee754@1.2.1: - resolution: { integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== } - dev: false - - /inherits@2.0.4: - resolution: { integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== } - dev: false - - /ipaddr.js@1.9.1: - resolution: { integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== } - engines: { node: '>= 0.10' } - dev: false - - /jsonparse@1.3.1: - resolution: { integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== } - engines: { '0': node >= 0.2.0 } - dev: false - - /media-typer@0.3.0: - resolution: { integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= } - engines: { node: '>= 0.6' } - dev: false - - /merge-descriptors@1.0.1: - resolution: { integrity: sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= } - dev: false - - /methods@1.1.2: - resolution: { integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== } - engines: { node: '>= 0.6' } - dev: false - - /mime-db@1.52.0: - resolution: { integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== } - engines: { node: '>= 0.6' } - dev: false - - /mime-types@2.1.35: - resolution: { integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== } - engines: { node: '>= 0.6' } - dependencies: - mime-db: 1.52.0 - dev: false - - /mime@1.6.0: - resolution: { integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== } - engines: { node: '>=4' } - hasBin: true - dev: false - - /ms@2.0.0: - resolution: { integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== } - dev: false - - /ms@2.1.3: - resolution: { integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== } - dev: false - - /negotiator@0.6.3: - resolution: { integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== } - engines: { node: '>= 0.6' } - dev: false - - /object-inspect@1.12.2: - resolution: { integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== } - dev: false - - /on-exit-leak-free@2.1.0: - resolution: { integrity: sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w== } - dev: false - - /on-finished@2.4.1: - resolution: { integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== } - engines: { node: '>= 0.8' } - dependencies: - ee-first: 1.1.1 - dev: false - - /parseurl@1.3.3: - resolution: { integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== } - engines: { node: '>= 0.8' } - dev: false - - /path-to-regexp@0.1.7: - resolution: { integrity: sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= } - dev: false - - /pino-abstract-transport@1.0.0: - resolution: { integrity: sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA== } - dependencies: - readable-stream: 4.2.0 - split2: 4.1.0 - dev: false - - /pino-std-serializers@6.0.0: - resolution: { integrity: sha512-mMMOwSKrmyl+Y12Ri2xhH1lbzQxwwpuru9VjyJpgFIH4asSj88F2csdMwN6+M5g1Ll4rmsYghHLQJw81tgZ7LQ== } - dev: false - - /pino@8.7.0: - resolution: { integrity: sha512-l9sA5uPxmZzwydhMWUcm1gI0YxNnYl8MfSr2h8cwLvOAzQLBLewzF247h/vqHe3/tt6fgtXeG9wdjjoetdI/vA== } - hasBin: true - dependencies: - atomic-sleep: 1.0.0 - fast-redact: 3.1.2 - on-exit-leak-free: 2.1.0 - pino-abstract-transport: 1.0.0 - pino-std-serializers: 6.0.0 - process-warning: 2.0.0 - quick-format-unescaped: 4.0.4 - real-require: 0.2.0 - safe-stable-stringify: 2.4.1 - sonic-boom: 3.2.0 - thread-stream: 2.2.0 - dev: false - - /process-warning@2.0.0: - resolution: { integrity: sha512-+MmoAXoUX+VTHAlwns0h+kFUWFs/3FZy+ZuchkgjyOu3oioLAo2LB5aCfKPh2+P9O18i3m43tUEv3YqttSy0Ww== } - dev: false - - /process@0.11.10: - resolution: { integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== } - engines: { node: '>= 0.6.0' } - dev: false - - /proxy-addr@2.0.7: - resolution: { integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== } - engines: { node: '>= 0.10' } - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - dev: false - - /qs@6.11.0: - resolution: { integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== } - engines: { node: '>=0.6' } - dependencies: - side-channel: 1.0.4 - dev: false - - /quick-format-unescaped@4.0.4: - resolution: { integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== } - dev: false - - /range-parser@1.2.1: - resolution: { integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== } - engines: { node: '>= 0.6' } - dev: false - - /raw-body@2.5.1: - resolution: { integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== } - engines: { node: '>= 0.8' } - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - dev: false - - /readable-stream@4.2.0: - resolution: { integrity: sha512-gJrBHsaI3lgBoGMW/jHZsQ/o/TIWiu5ENCJG1BB7fuCKzpFM8GaS2UoBVt9NO+oI+3FcrBNbUkl3ilDe09aY4A== } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } - dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - dev: false - - /real-require@0.2.0: - resolution: { integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg== } - engines: { node: '>= 12.13.0' } - dev: false - - /redis@4.5.0: - resolution: { integrity: sha512-oZGAmOKG+RPnHo0UxM5GGjJ0dBd/Vi4fs3MYwM1p2baDoXC0wpm0yOdpxVS9K+0hM84ycdysp2eHg2xGoQ4FEw== } - dependencies: - '@redis/bloom': 1.1.0(@redis/client@1.4.0) - '@redis/client': 1.4.0 - '@redis/graph': 1.1.0(@redis/client@1.4.0) - '@redis/json': 1.0.4(@redis/client@1.4.0) - '@redis/search': 1.1.0(@redis/client@1.4.0) - '@redis/time-series': 1.0.4(@redis/client@1.4.0) - dev: false - - /safe-buffer@5.2.1: - resolution: { integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== } - dev: false - - /safe-stable-stringify@2.4.1: - resolution: { integrity: sha512-dVHE6bMtS/bnL2mwualjc6IxEv1F+OCUpA46pKUj6F8uDbUM0jCCulPqRNPSnWwGNKx5etqMjZYdXtrm5KJZGA== } - engines: { node: '>=10' } - dev: false - - /safer-buffer@2.1.2: - resolution: { integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== } - dev: false - - /send@0.18.0: - resolution: { integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== } - engines: { node: '>= 0.8.0' } - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - dev: false - - /serve-static@1.15.0: - resolution: { integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== } - engines: { node: '>= 0.8.0' } - dependencies: - encodeurl: 1.0.2 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.18.0 - transitivePeerDependencies: - - supports-color - dev: false - - /setprototypeof@1.2.0: - resolution: { integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== } - dev: false - - /side-channel@1.0.4: - resolution: { integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== } - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.1.3 - object-inspect: 1.12.2 - dev: false - - /sonic-boom@3.2.0: - resolution: { integrity: sha512-SbbZ+Kqj/XIunvIAgUZRlqd6CGQYq71tRRbXR92Za8J/R3Yh4Av+TWENiSiEgnlwckYLyP0YZQWVfyNC0dzLaA== } - dependencies: - atomic-sleep: 1.0.0 - dev: false - - /split2@4.1.0: - resolution: { integrity: sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ== } - engines: { node: '>= 10.x' } - dev: false - - /statuses@2.0.1: - resolution: { integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== } - engines: { node: '>= 0.8' } - dev: false - - /streamsearch@1.1.0: - resolution: { integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== } - engines: { node: '>=10.0.0' } - dev: false - - /thread-stream@2.2.0: - resolution: { integrity: sha512-rUkv4/fnb4rqy/gGy7VuqK6wE1+1DOCOWy4RMeaV69ZHMP11tQKZvZSip1yTgrKCMZzEMcCL/bKfHvSfDHx+iQ== } - dependencies: - real-require: 0.2.0 - dev: false - - /through@2.3.8: - resolution: { integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== } - dev: false - - /toidentifier@1.0.1: - resolution: { integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== } - engines: { node: '>=0.6' } - dev: false - - /type-is@1.6.18: - resolution: { integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== } - engines: { node: '>= 0.6' } - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - dev: false - - /typescript@4.8.4: - resolution: { integrity: sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== } - engines: { node: '>=4.2.0' } - hasBin: true - dev: true - - /undici@5.22.1: - resolution: { integrity: sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw== } - engines: { node: '>=14.0' } - dependencies: - busboy: 1.6.0 - dev: false - - /unpipe@1.0.0: - resolution: { integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== } - engines: { node: '>= 0.8' } - dev: false - - /utils-merge@1.0.1: - resolution: { integrity: sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= } - engines: { node: '>= 0.4.0' } - dev: false - - /vary@1.1.2: - resolution: { integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== } - engines: { node: '>= 0.8' } - dev: false - - /ws@8.11.0: - resolution: { integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== } - 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 - dev: false - - /yallist@4.0.0: - resolution: { integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== } - dev: false diff --git a/server/src/redis/streamFromRedis.ts b/server/src/redis/streamFromRedis.ts index 043e5e5..fff594d 100644 --- a/server/src/redis/streamFromRedis.ts +++ b/server/src/redis/streamFromRedis.ts @@ -1,5 +1,4 @@ import { getRedisClient } from "./getRedisClient.js" -import { EventEmitter } from "events" import { listenRedisStream } from "./listenRedisStream.js" import { streamFromRedisLogger as logger } from "../utils/loggers.js" import { setTimeout } from "node:timers/promises" @@ -9,17 +8,10 @@ import { updateSchemaForEvent } from "../schemas/maintainSchemas.js" import { VisitorCounterService } from "./visitorCounter.js" import { Elysia } from "elysia" -console.log("Running API server", process.version) - -const eventEmitter = new EventEmitter({}) -eventEmitter.setMaxListeners(1_000_000) // increase max listeners (this is clients x num of streams) - const app = new Elysia() -let clients = 0 - app.get("/health", async ({ request }) => { const commandClient = await getRedisClient() - const health = { currentWsConnections: 0, connections: clients } + const health = { currentWsConnections: 0, connections: app.server?.pendingWebSockets } for (const streamPath of streamPaths) { const lastHeartbeat = await commandClient.hGet("heartbeats", streamPath).then(t => new Date(parseInt(t || "0"))) health[streamPath] = Date.now() - lastHeartbeat.getTime() < 60_000 // more than 60 seconds indicates stream offline @@ -128,62 +120,56 @@ app.get("/visitors/:date", async ({ params, set }) => { } }) -function getListenerCounts() { - const counts: Record = {} - for (const streamPath of streamPaths) - counts[streamPath] = eventEmitter.listenerCount(streamPath) - return counts -} - -const totalListeners = () => Object.values(getListenerCounts()).reduce((p, c) => p + c) - +const ac = new AbortController() +const { signal } = ac +let unclosedWsCount = 0 // web socket server for sending events to client app.ws("/events", { async open(ws) { - // console.log("Open data", ws.data) - // subscribe to all events + unclosedWsCount++ + // subscribe to all streams and increment counter of connections for (const streamPath of streamPaths) { - eventEmitter.addListener(streamPath, ws.send) + ws.subscribe(streamPath) } const ipAddress = String(ws.data.headers["x-forwarded-for"]) - console.log({ ipAddress }) if (ipAddress) await visitorCounter.count(ipAddress) else logger.info("No IP Address forwarded, skipping update to visitor statistics") - clients++ const redisCount = await counterClient.incr("currentWsConnections") - console.log("Websocket connected.", totalListeners(), "event listeners", { clients, redisCount }) - eventEmitter.on("close", () => ws.terminate()) + console.log("Websocket connected.", { clients: app.server?.pendingWebSockets, redisCount }) + signal.addEventListener("abort", () => ws.close()) }, async close(ws, code, reason) { - console.log("Close data", ws.data) - // decrement counter + // decrement connections counter and unsubscribe from all streams for (const streamPath of streamPaths) - eventEmitter.removeListener(streamPath, ws.send) - clients-- + ws.unsubscribe(streamPath) // don't think this is necessary, surely its done automatically when a socket terminates const redisCount = await counterClient.decr("currentWsConnections") - console.log("Websocket disconnected with code.", code, totalListeners(), "event listeners", { clients, redisCount }) + console.log("Websocket disconnected with code.", code, { clients: app.server?.pendingWebSockets, redisCount }) + unclosedWsCount-- } }) app.on("request", ({ request }) => console.log("Request to server", request.url)) -const server = app.listen(3000, () => console.log("Elysia Listening on port 3000")) - +app.listen(3000, () => console.log("Elysia Listening on port 3000")) -const ac = new AbortController() -const { signal } = ac async function shutdown() { + const requestTime = Bun.nanoseconds() try { logger.flush() - console.log("Graceful shutdown", new Date()) - eventEmitter.emit("close") // this will terminate all websockets - eventEmitter.removeAllListeners() + console.log("Graceful shutdown commenced", new Date()) ac.abort() - await setTimeout(250) // wait for websockets to be closed gracefully before quiting the Redis client + while (unclosedWsCount) { + if (Bun.nanoseconds() - requestTime > 2 * 1_000_000_000) break // don't keep trying if its not working after 2 sec + await setTimeout(5) // wait for websockets to be closed gracefully before quiting the Redis client + } + const waitingNs = Bun.nanoseconds() - requestTime + console.log("Closed all client connections after", waitingNs / 1000 / 1000, "ms") + await app.stop() await counterClient.quit() logger.flush() - await app.stop() } finally { + const waitingNs = Bun.nanoseconds() - requestTime + console.log("Graceful shutdown finished", new Date(), "in", waitingNs / 1000 / 1000, "ms") process.exit() } } @@ -196,7 +182,7 @@ const eventStream = listenRedisStream({ streamKeys: [...streamPaths].map(stream for await(const event of eventStream) { const streamPath = event.stream.split(":")[1] let parsedEvent = JSON.parse(event.data.event) - eventEmitter.emit(streamPath, { streamPath, ...parsedEvent }) + app.server?.publish(streamPath, { streamPath, ...parsedEvent }) if (streamPath === "companies") await saveCompanyNumber(counterClient, parsedEvent, streamPath) .catch(e => logger.error(e, "Error saving company number")) diff --git a/server/src/redis/streamToRedis.ts b/server/src/redis/streamToRedis.ts index 32a4628..ebef229 100644 --- a/server/src/redis/streamToRedis.ts +++ b/server/src/redis/streamToRedis.ts @@ -24,11 +24,11 @@ const sendEvent = streamPath => event => client.xAdd("events:" + streamPath, eve strategyModifier: "~" } }) -const incrEventCount = streamPath => event => client.hIncrBy(`counts:${streamPath}:daily`, new Date().toISOString().split('T')[0], 1) +const incrEventCount = streamPath => event => client.hIncrBy(`counts:${streamPath}:daily`, new Date().toISOString().split("T")[0], 1) const incrResourceKindCount = streamPath => event => client.hIncrBy(`resourceKinds:${streamPath}`, event.resource_kind, 1) -const updateTimepoint = streamPath => event => client.hSet('timepoints', streamPath, JSON.stringify(event.event)) +const updateTimepoint = streamPath => event => client.hSet("timepoints", streamPath, JSON.stringify(event.event)) const heartbeat = streamPath => () => client.hSet("heartbeats", streamPath, Date.now()) // keeps track of which are alive -const getMostRecentTimepoint = streamPath => client.hGet('timepoints', streamPath).then(r => r ? JSON.parse(r)?.timepoint : undefined) +const getMostRecentTimepoint = streamPath => client.hGet("timepoints", streamPath).then(r => r ? JSON.parse(r)?.timepoint : undefined) const startStream = streamPath => getMostRecentTimepoint(streamPath) .then((timepoint) => stream(streamPath, timepoint) .on("data", sendEvent(streamPath)) diff --git a/server/test/benchmark.ts b/server/test/benchmark.ts new file mode 100644 index 0000000..e42cb01 --- /dev/null +++ b/server/test/benchmark.ts @@ -0,0 +1,18 @@ +import { run, bench } from "mitata" +import assert from "node:assert/strict" + +const urls = [ + new URL("/randomCompanyNumbers", "http://localhost:3000"), + new URL("/events/randomCompanyNumbers", "http://localhost"), + new URL("/events/randomCompanyNumbers", "https://companies.stream") +] + +for (const url of urls) { + bench(url.toString(), async () => { + const res = await fetch(url) + assert(res.ok, "Bad response status code") + }) +} + + +await run({})