oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
73.96k stars 2.75k forks source link

[Feature Request] Clustered Threading cluster_threads module like cluster module that supports sharing (or different ports) a port for listening #7349

Open ganeshkbhat opened 11 months ago

ganeshkbhat commented 11 months ago

What is the problem this feature would solve?

Clustering of threads, basically similar to clustered thread pools with features same as Cluster module.

https://github.com/ganeshkbhat/loadbalancer/blob/4f15c79434797ccaf17aeae6f6a3f4c47f0e5703/nodejs.proposal.md

I am recommend implementing cluster_thread module which is genuinely a good starting point for creating clusters of threads like clusters of processes in node.js. Currently a multi-threading option is a little buggy. There is no random round robin as well in Windows due to absence of file descriptor module [presumed - check] in windows environment.

This is the Node.js Suggestion recommendation. https://github.com/nodejs/node/issues/48350

What is the feature you are proposing to solve the problem?

Clustered threads module: The module Clustered threads module which is basically Clustering of threads will be similar to clustered thread pools with features same as inbuilt Cluster module based on child_process.fork() features with minor differences.

Clustering of threads, basically similar to Cluster module where each thread based on specification can:

  1. listen to same port
  2. listen to different ports

Background:

nodejs module: cluster cluster

  1. The worker processes are spawned using the child_process.fork() method, so that they can communicate with the parent via IPC and pass server handles back and forth.

  2. The cluster module supports two methods of distributing incoming connections.

    • The first one (and the default one on all platforms except Windows) is the round-robin approach, where the primary process listens on a port
    • The second approach is where the primary process creates the listen socket and sends it to interested workers.
  3. Because server.listen() hands off most of the work to the primary process, there are three cases where the behavior between a normal Node.js process and a cluster worker differs:

    a.) server.listen({fd: 7}) Because the message is passed to the primary, file descriptor 7 in the parent will be listened on, and the handle passed to the worker, rather than listening to the worker's idea of what the number 7 file descriptor references.

    b.) server.listen(handle) Listening on handles explicitly will cause the worker to use the supplied handle, rather than talk to the primary process.

    c.) server.listen(0) Normally, this will cause servers to listen on a random port. However, in a cluster, each worker will receive the same "random" port each time they do listen(0). In essence, the port is random the first time, but predictable thereafter. To listen on a unique port, generate a port number based on the cluster worker ID.

CHILD PROCESS PORT SHARING:

if (cluster.isPrimary) { console.log(Primary ${process.pid} is running);

// Fork workers. for (let i = 0; i < numCPUs; i++) { cluster.fork(); }

cluster.on('exit', (worker, code, signal) => { console.log(worker ${worker.process.pid} died); }); } else { http.createServer((req, res) => { res.writeHead(200); res.end('hello world\n'); }).listen(8000);

console.log(Worker ${process.pid} started); }


* `shares a different port` [process.different.port.js](https://github.com/ganeshkbhat/loadbalancer/blob/4f15c79434797ccaf17aeae6f6a3f4c47f0e5703/demos/process.different.port.js):
```js
const cluster = require('node:cluster');
const http = require('node:http');
const numCPUs = require('node:os').availableParallelism();
const process = require('node:process');

if (cluster.isPrimary) {
  console.log(`Primary ${process.pid} is running`);

  // Fork workers.
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`worker ${worker.process.pid} died`);
  });
} else {
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('hello world\n');
  }).listen(process.pid);

  console.log(`Worker ${process.pid} started`);
}

RECOMMENDED AND EXPECTED WORKER THREAD CLUSTER MODULE AND PORT SHARING like cluster module:

const cluster_thread = require('node:cluster_thread');
const http = require('node:http');
const numCPUs = require('node:os').availableParallelism();
const process = require('node:process');
let workers = [];

if (cluster_thread.isPrimary) {
  console.log(`Primary ${process.pid} is running`);

  // Fork workers.
  for (let i = 0; i < numCPUs; i++) {
    workers[i] = new cluster_thread.Worker(__filename, {
        workerData: script,
    });
  }

  workers[i].on('exit', (worker, code, signal) => {
   console.log(`worker ${worker.process.pid} died`);
  });
} else {
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('hello world\n');
  }).listen(8000);

  console.log(`Worker ${process.pid}, ${cluster_thread.worker.threadId} started`);
}

if (cluster_thread.isMainThread) { console.log(Primary ${process.pid} is running);

// Fork workers. for (let i = 0; i < numCPUs; i++) { workers[i] = new cluster_thread.Worker(__filename, { workerData: script, }); }

workers[i].on('exit', (worker, code, signal) => { console.log(worker ${worker.process.pid} died); }); } else { http.createServer((req, res) => { res.writeHead(200); res.end('hello world\n'); }).listen(cluster_thread.worker.threadId);

console.log(Worker ${process.pid}, ${cluster_thread.worker.threadId} started); }



### What alternatives have you considered?

#### `nodejs module: cluster` [cluster](https://nodejs.org/api/cluster.html#how-it-works) based on `child_process` will be more resource intensive than worker_threads based `cluster_threads` module
melroy89 commented 10 months ago

Is this not just a duplicate of https://github.com/oven-sh/bun/issues/2428 ?

ganeshkbhat commented 10 months ago

@melroy89 No this #2428 is for cluster_threads [multi-threading] not cluster multi-processing that implements clustering or the child_processes