Compare commits

...

2 Commits

Author SHA1 Message Date
Jarred Sumner
3af53d65d8 Fix websocket CPU usage issue 2025-11-20 23:15:41 -08:00
Jarred Sumner
423608ce55 Create bun-websocket-cpu-fixture.js 2025-11-20 23:06:17 -08:00
3 changed files with 78 additions and 1 deletions

View File

@@ -703,7 +703,7 @@ int ssl_is_low_prio(struct us_internal_ssl_socket_t *s) {
* step is CPU intensive, and we want to speed up the rest of connection
* establishing if the CPU intensive work is already done, so fully
* established connections increase lineary over time under high load */
return SSL_in_init(s->ssl);
return SSL_get_state(s->ssl) & SSL_ST_BEFORE;
}
/* Per-context functions */

View File

@@ -0,0 +1,65 @@
import path from "path";
const server = Bun.serve({
port: 0,
idleTimeout: 100,
tls: {
cert: Bun.file(path.join(import.meta.dir, "fixtures", "cert.pem")),
key: Bun.file(path.join(import.meta.dir, "fixtures", "cert.key")),
},
fetch(req, server) {
if (server.upgrade(req)) {
return;
}
return new Response("Upgrade failed", { status: 500 });
},
websocket: {
idleTimeout: 120,
open(ws) {},
message(ws, message) {
ws.send(message);
},
},
});
const ws = new WebSocket(`wss://${server.hostname}:${server.port}`, { tls: { rejectUnauthorized: false } });
await Bun.sleep(1000);
for (let i = 0; i < 1000; i++) {
ws.send("hello");
}
let bytesReceived = 0;
ws.onmessage = event => {
bytesReceived += event.data.length;
};
let previousUsage = process.cpuUsage();
let previousTime = Date.now();
let count = 0;
setInterval(() => {
count++;
const currentUsage = process.cpuUsage(previousUsage);
const currentTime = Date.now();
const userCpuTime = currentUsage.user; // microseconds
const systemCpuTime = currentUsage.system; // microseconds
const totalCpuTime = userCpuTime + systemCpuTime;
const timeDeltaMs = currentTime - previousTime; // milliseconds
const timeDeltaMicroseconds = timeDeltaMs * 1000; // convert to microseconds
// Calculate percentage for the current process
const cpuUsagePercentage = (totalCpuTime / timeDeltaMicroseconds) * 100;
console.log(`CPU Usage: ${cpuUsagePercentage.toFixed(2)}%`);
previousUsage = process.cpuUsage(); // Update for the next interval
previousTime = currentTime;
if (count == 2) {
server.stop(true);
// The expected value is around 0.XX%, but we allow a 10% margin of error to account for potential flakiness.
process.exit(cpuUsagePercentage < 10 ? 0 : 1);
}
}, 1000);

View File

@@ -2189,3 +2189,15 @@ it.concurrent("#20283", async () => {
// there should be no cookies and the clone should have succeeded
expect(json).toEqual({ cookies: {}, clonedCookies: {} });
});
it.concurrent("should not use 100% CPU when idle", async () => {
await using proc = Bun.spawn({
cmd: [bunExe(), join(import.meta.dir, "bun-websocket-cpu-fixture.js")],
env: bunEnv,
stdout: "inherit",
stderr: "inherit",
stdin: "inherit",
});
const code = await proc.exited;
expect(code).toBe(0);
});