I am migrating my uWS node.js server to be multithreaded. However, when I try to list different ports to connect to (e.g. localhost:3000/t1 and localhost:3000/t2), only one of the connections works.
I tried this:
const uWS = require('uWebSockets.js');
const port = 3000;
let { Worker, isMainThread, threadId } = require('worker_threads');
const os = require('os');
if (isMainThread) {
[0, 1].forEach(() => {
new Worker(__filename);
});
} else {
const wsLocation = '/' + threadId;
uWS.App().ws(wsLocation, {
open: (ws, req) => {
console.log('ws connected to worker! GG ' + threadId);
},
}).listen(port, (token) => {
if (token) {
console.log('Listening to port ' + port + ' from thread ' + threadId);
} else {
console.log('Failed to listen to port ' + port + ' from thread ' + threadId);
}
});
}
The console tells me that both servers /t1 and /t2 have been listed, although when i try to connect like this:
const url = 'ws://localhost:3000/1';
// i test the previous line with 'ws://localhost:3000/2' as well
const client = new WebSocket(url);
client.onopen = () => {
console.log('WebSocket connection opened');
}
... one connection works and the other fails. The node.js console tells me that the first webserver that starts wins, meaning if thread t1 gets its webserver ready first then from t1 will be valid and t2 will be invalid.
Why don't both ports list? Why can't i connect to both? I am on windows.
Hopefully your Problem is solved By now but as mentioned in the example in the Docs , the above works only on Linux where port sharing is supported by the Kernel
/* This example shows two different approaches to multi-core load balancing.
* The first approach (the oldest) requires Linux and will only work on Linux.
* This approach listens to port 4000 on all CPUs. That's it. That's all you do.
* Listening to the same port from many worker threads will work on Linux.
* The second approach will work on all platforms; you set up a main acceptorApp and register all child apps
* (worker apps) with it. The acceptorApp will listen to port 9001 and move sockets in round-robin fashion to
* the registered child apps.
* Note that, in this example we only create 2 worker threads. Ideally you should create as many as there are CPUs
* in your system. But by only creating 2 here, it is simple to see the perf. gain on a system of 4 cores, as you can then
* run the client side on the remaining 2 cores without interfering with the server side. */
const uWS = require('uWebSockets.js');
const port = 9001;
const { Worker, isMainThread, threadId, parentPort } = require('worker_threads');
const os = require('os');
if (isMainThread) {
/* The acceptorApp only listens, but must be SSL if worker apps are SSL and likewise opposite */
const acceptorApp = uWS./*SSL*/App({
key_file_name: 'misc/key.pem',
cert_file_name: 'misc/cert.pem',
passphrase: '1234'
}).listen(port, (token) => {
if (token) {
console.log('Listening to port ' + port + ' from thread ' + threadId + ' as main acceptor');
} else {
console.log('Failed to listen to port ' + port + ' from thread ' + threadId);
}
});
/* Main thread loops over all CPUs */
/* In this case we only spawn two (hardcoded) */
/*os.cpus()*/[0, 1].forEach(() => {
/* Spawn a new thread running this source file */
new Worker(__filename).on("message", (workerAppDescriptor) => {
acceptorApp.addChildAppDescriptor(workerAppDescriptor);
});
});
/* I guess main thread joins by default? */
} else {
/* Here we are inside a worker thread */
const app = uWS./*SSL*/App({
key_file_name: 'misc/key.pem',
cert_file_name: 'misc/cert.pem',
passphrase: '1234'
}).get('/*', (res, req) => {
res.end('Hello Worker!');
}).listen(4000, (token) => {
if (token) {
console.log('Listening to port ' + 4000 + ' from thread ' + threadId);
} else {
console.log('Failed to listen to port ' + 4000 + ' from thread ' + threadId);
}
});
/* The worker sends back its descriptor to the main acceptor */
parentPort.postMessage(app.getDescriptor());
}