From 87dbc350f0bb7a59dd8f51324ab513009dcddad4 Mon Sep 17 00:00:00 2001 From: Matthew W Date: Wed, 15 Jan 2025 16:40:40 +1100 Subject: [PATCH] feat(examples/benchmarks): add suite for pushing events to individual sessions --- examples/benchmarks/benchmark.ts | 3 +- examples/benchmarks/lib/createEventSource.ts | 4 +- .../benchmarks/suites/channel-broadcast.ts | 20 ++-- examples/benchmarks/suites/session-push.ts | 98 +++++++++++++++++++ examples/package-lock.json | 33 ++++++- examples/package.json | 4 +- 6 files changed, 146 insertions(+), 16 deletions(-) create mode 100644 examples/benchmarks/suites/session-push.ts diff --git a/examples/benchmarks/benchmark.ts b/examples/benchmarks/benchmark.ts index b62728c..954f058 100644 --- a/examples/benchmarks/benchmark.ts +++ b/examples/benchmarks/benchmark.ts @@ -1,6 +1,7 @@ import {suite as suiteChannelBroadcast} from "./suites/channel-broadcast"; +import {suite as suiteSessionPush} from "./suites/session-push"; -Promise.all([suiteChannelBroadcast.setup()]).then((suites) => { +Promise.all([suiteSessionPush.setup()]).then((suites) => { for (const suite of suites) { suite.run(); } diff --git a/examples/benchmarks/lib/createEventSource.ts b/examples/benchmarks/lib/createEventSource.ts index b201b0f..a246bed 100644 --- a/examples/benchmarks/lib/createEventSource.ts +++ b/examples/benchmarks/lib/createEventSource.ts @@ -1,4 +1,4 @@ -import { EventSource } from "eventsource"; +import {EventSource} from "eventsource"; const createEventSource = (port: number, path = "/sse") => { const url = `http://localhost:${port}${path}`; @@ -10,4 +10,4 @@ const createEventSource = (port: number, path = "/sse") => { }); }; -export { createEventSource }; +export {createEventSource}; diff --git a/examples/benchmarks/suites/channel-broadcast.ts b/examples/benchmarks/suites/channel-broadcast.ts index 82e5db3..4f90535 100644 --- a/examples/benchmarks/suites/channel-broadcast.ts +++ b/examples/benchmarks/suites/channel-broadcast.ts @@ -1,19 +1,15 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ - -import { createChannel, createSession } from "better-sse"; +import {createChannel, createSession} from "better-sse"; // @ts-ignore import EasySse from "easy-server-sent-events"; // @ts-ignore import SseChannel from "sse-channel"; -import { createClientPool } from "../lib/createClientPool"; -import { Suite } from "./Suite"; +import {createClientPool} from "../lib/createClientPool"; +import {Suite} from "./Suite"; export const suite = new Suite("Broadcast events with channels", async () => { const numberOfClients = 10; await suite.addBenchmark("better-sse", async (server, port, listen) => { - let count = 0; - const channel = createChannel(); server.get("/sse", async (req, res) => { @@ -22,6 +18,8 @@ export const suite = new Suite("Broadcast events with channels", async () => { await listen(); + let count = 0; + return { run: () => { channel.broadcast(++count); @@ -33,7 +31,7 @@ export const suite = new Suite("Broadcast events with channels", async () => { await suite.addBenchmark("sse-channel", async (server, port, listen) => { let count = 0; - const channel = new SseChannel({ jsonEncode: true }); + const channel = new SseChannel({jsonEncode: true}); server.get("/sse", (req, res) => { channel.addClient(req, res); @@ -58,9 +56,7 @@ export const suite = new Suite("Broadcast events with channels", async () => { await suite.addBenchmark( "easy-server-sent-events", async (server, port, listen) => { - let count = 0; - - const { SSE, send } = EasySse({ endpoint: "/sse" }); + const {SSE, send} = EasySse({endpoint: "/sse"}); server.get("/sse", (req, res, next) => { SSE(req, res, next); @@ -69,6 +65,8 @@ export const suite = new Suite("Broadcast events with channels", async () => { await listen(); + let count = 0; + return { run: () => { send("all", "message", ++count); diff --git a/examples/benchmarks/suites/session-push.ts b/examples/benchmarks/suites/session-push.ts new file mode 100644 index 0000000..821eb6f --- /dev/null +++ b/examples/benchmarks/suites/session-push.ts @@ -0,0 +1,98 @@ +import {createServer as createRawHttpServer} from "node:http"; +import {type Session, createSession} from "better-sse"; +import type {Response as ExpressResponse} from "express"; +import SSE, {type Client} from "sse"; +// @ts-ignore +import SseChannel from "sse-channel"; +import {createEventSource} from "../lib/createEventSource"; +import {Suite} from "./Suite"; + +export const suite = new Suite("Push events with sessions", async () => { + await suite.addBenchmark("better-sse", async (server, port, listen) => { + let session: Session; + + server.get("/sse", async (req, res) => { + session = await createSession(req, res); + }); + + await listen(); + + const eventSource = await createEventSource(port); + + let count = 0; + + return { + run: () => { + session.push(++count); + }, + teardown: () => eventSource.close(), + }; + }); + + await suite.addBenchmark("sse-channel", async (server, port, listen) => { + const channel = new SseChannel({jsonEncode: true}); + + let res: ExpressResponse; + + server.get("/sse", (req, _res) => { + res = _res; + channel.addClient(req, res); + }); + + await listen(); + + const eventSource = await createEventSource(port); + + let count = 0; + + return { + run: () => { + ++count; + + channel.send( + { + event: "message", + data: count, + id: count, + }, + [res] + ); + }, + teardown: () => eventSource.close(), + }; + }); + + await suite.addBenchmark("sse", async (server) => { + const port = ++Suite.port; + + // `sse` package cannot attach to an Express instance directly, so wrap with a raw Node HTTP server + const wrapper = createRawHttpServer(server); + + const sse = new SSE(wrapper); + + let client: Client; + + sse.on("connection", (_client) => { + client = _client; + }); + + await new Promise((resolve) => wrapper.listen(port, () => resolve())); + + const eventSource = await createEventSource(port); + + let count = 0; + + return { + run: () => { + const stringified = (count++).toString(); + + client.send({ + event: "message", + data: stringified, + id: stringified, + }); + }, + teardown: () => eventSource.close(), + }; + }); +}); diff --git a/examples/package-lock.json b/examples/package-lock.json index ce37069..e0801cb 100644 --- a/examples/package-lock.json +++ b/examples/package-lock.json @@ -16,6 +16,7 @@ "express": "^4.21.1", "node-os-utils": "^1.3.7", "pem": "^1.14.8", + "sse": "^0.0.8", "sse-channel": "^4.0.0", "ts-node": "^10.9.2", "ts-node-dev": "^2.0.0" @@ -25,7 +26,8 @@ "@types/express": "^5.0.0", "@types/node": "^20.16.12", "@types/node-os-utils": "^1.3.4", - "@types/pem": "^1.14.4" + "@types/pem": "^1.14.4", + "@types/sse": "^0.0.0" } }, "node_modules/@cspotcode/source-map-support": { @@ -220,6 +222,16 @@ "@types/send": "*" } }, + "node_modules/@types/sse": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@types/sse/-/sse-0.0.0.tgz", + "integrity": "sha512-5gFwbzDsaCze6/SYNwOmk/F24+gtXwTX3at12rJMDo7+VLi3jI83j5h5IkdXEvGakTkVIF9VQBxWOensz+LBWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", @@ -1238,6 +1250,14 @@ "wrappy": "1" } }, + "node_modules/options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha512-bOj3L1ypm++N+n7CEbbe473A414AB7z+amKYshRb//iuL3MpdDCLhPnw6aVTdKB9g5ZRVHIEp8eUln6L2NUStg==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -1590,6 +1610,17 @@ "source-map": "^0.6.0" } }, + "node_modules/sse": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/sse/-/sse-0.0.8.tgz", + "integrity": "sha512-cviG7JH31TUhZeaEVhac3zTzA+2FwA7qvHziAHpb7mC7RNVJ/RbHN+6LIGsS2ugP4o2H15DWmrSMK+91CboIcg==", + "dependencies": { + "options": "0.0.6" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/sse-channel": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/sse-channel/-/sse-channel-4.0.0.tgz", diff --git a/examples/package.json b/examples/package.json index 7759aea..004f08b 100644 --- a/examples/package.json +++ b/examples/package.json @@ -15,6 +15,7 @@ "express": "^4.21.1", "node-os-utils": "^1.3.7", "pem": "^1.14.8", + "sse": "^0.0.8", "sse-channel": "^4.0.0", "ts-node": "^10.9.2", "ts-node-dev": "^2.0.0" @@ -24,6 +25,7 @@ "@types/express": "^5.0.0", "@types/node": "^20.16.12", "@types/node-os-utils": "^1.3.4", - "@types/pem": "^1.14.4" + "@types/pem": "^1.14.4", + "@types/sse": "^0.0.0" } }