Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ export class Jetpath {
& Record<string, any>;
}
async listen(): Promise<void> {
this.server = server(this.plugs, this.options);
if (this.server.isPrimary) {
this.server.listen(this.options.port);
this.listening = true;
this._nativeServer = this.server;
return;
}

// ? {-view-} here is replaced at build time to html
const UI = await readFile(html_path, {
encoding: "utf-8",
Expand Down Expand Up @@ -188,9 +196,7 @@ export class Jetpath {

//
assignMiddleware(_JetPath_paths, _jet_middleware);
// ? start server
// ? check if server is already listening
this.server = server(this.plugs, this.options);

// ? add plugins to the server
if (
this.server.edge &&
Expand Down
42 changes: 41 additions & 1 deletion src/primitives/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,13 @@ export const _jet_middleware: Record<
export const server = (
plugs: JetPlugin[],
options: jetOptions,
): { listen: any; edge: boolean } => {
): {
listen: any;
edge: boolean;
isPrimary?: boolean;
stop?: () => void;
close?: (cb?: () => void) => void;
} => {
let server;
let server_else;
const runtimeConfig = options.runtimes;
Expand Down Expand Up @@ -144,6 +150,40 @@ export const server = (
};
}
if (runtime["bun"]) {
const clusterConfig = runtimeConfig?.bun?.cluster;
if (clusterConfig) {
const cluster = require("node:cluster");
const os = require("node:os");

if (cluster.isPrimary) {
Comment on lines +154 to +158
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Does Bun support node:cluster module for worker processes?

💡 Result:

Yes, Bun supports the node:cluster module for worker processes. It was implemented in Bun v1.1.25 (August 2024) via PR #11492 and is documented in the official Bun API reference. However, it has limitations: handles and file descriptors cannot be passed between workers (limiting TCP server load-balancing to Linux via SO_REUSEPORT), and it is described as "implemented but not battle-tested."

Citations:


Verify Bun's node:cluster support meets production requirements.

Bun supports node:cluster (as of v1.1.25), but with important limitations: handles and file descriptors cannot be passed between workers, and TCP server load-balancing on Bun is limited to Linux using SO_REUSEPORT. Additionally, the feature is documented as "implemented but not battle-tested." Ensure the implementation accounts for these constraints and is tested on the target platform before production deployment.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/primitives/functions.ts` around lines 154 - 158, The code uses
node:cluster when clusterConfig is set (see clusterConfig,
require("node:cluster"), cluster.isPrimary) but Bun's cluster support is limited
and not battle-tested; update the implementation to detect Bun (e.g.,
process.release?.name === "bun") and either disable/skip the cluster branch or
emit a clear runtime error/log when running under Bun, and add guardrails to
avoid passing handles/file descriptors between workers and to require Linux +
SO_REUSEPORT for TCP load-balancing; also add a TODO/test note to verify cluster
behavior on the target platform before enabling in production.

const numWorkers = typeof clusterConfig === "number"
? clusterConfig
: os.cpus().length;
Comment on lines +159 to +161
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Validate that worker count is a positive integer.

If a user passes 0 or a negative number for cluster, the loop won't fork any workers, leaving the server non-functional without any error message.

🛡️ Suggested validation
       if (cluster.isPrimary) {
-        const numWorkers = typeof clusterConfig === "number"
-          ? clusterConfig
-          : os.cpus().length;
+        const numWorkers = typeof clusterConfig === "number"
+          ? Math.max(1, Math.floor(clusterConfig))
+          : os.cpus().length;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const numWorkers = typeof clusterConfig === "number"
? clusterConfig
: os.cpus().length;
const numWorkers = typeof clusterConfig === "number"
? Math.max(1, Math.floor(clusterConfig))
: os.cpus().length;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/primitives/functions.ts` around lines 159 - 161, The numWorkers
assignment using clusterConfig can accept 0 or negatives; validate clusterConfig
before using it: in the code that computes numWorkers (referencing clusterConfig
and numWorkers), check that clusterConfig is a positive integer via
Number.isInteger(clusterConfig) && clusterConfig > 0; if invalid, either throw a
descriptive error (e.g., "cluster must be a positive integer") or fall back to
os.cpus().length — implement one consistent behavior and update the numWorkers
assignment to use the validated value.


server = {
listen(port: number) {
LOG.log(`Primary ${process.pid} is starting ${numWorkers} workers`, "info");
for (let i = 0; i < numWorkers; i++) {
cluster.fork();
}

cluster.on("exit", (worker: any) => {
LOG.log(`worker ${worker.process.pid} died, restarting...`, "warn");
cluster.fork();
});
},
stop() {
for (const id in cluster.workers) {
cluster.workers[id].kill();
}
},
Comment on lines +175 to +179
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add null check before calling kill() on worker.

Workers can exit between iteration start and the kill() call, making cluster.workers[id] potentially undefined.

🛡️ Suggested fix
           stop() {
             for (const id in cluster.workers) {
-              cluster.workers[id].kill();
+              cluster.workers[id]?.kill();
             }
           },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
stop() {
for (const id in cluster.workers) {
cluster.workers[id].kill();
}
},
stop() {
for (const id in cluster.workers) {
cluster.workers[id]?.kill();
}
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/primitives/functions.ts` around lines 175 - 179, The stop() method
iterates cluster.workers and calls kill() without guarding against a worker
becoming undefined; update stop() to check that cluster.workers[id] is truthy
(e.g., !== undefined/null) before calling its kill() method so you don't attempt
to call kill() on a removed/exit worker; locate the stop() function in
primitives/functions.ts and add a simple null/undefined guard around the
cluster.workers[id].kill() call.

edge: false,
isPrimary: true,
};
return server;
}
}

if (options.upgrade && options.upgrade === true) {
server = {
listen(port: number) {
Expand Down
1 change: 1 addition & 0 deletions src/primitives/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ export type jetOptions = {
runtimes?: {
bun?: {
reusePort?: boolean;
cluster?: boolean | number;
};
deno?: {};
node?: {};
Expand Down