nodejs cluster module - Address in use error - javascript

I have an express.js application and it has to run a sub-process everytime there is a particular request (here it is : /compute/real-time ). There will be user-created scripts to compute the data. So, I am using node cluster module to create a pool of workers and pick the one which is free to execute the scripts. But I have hit the wall during the creation of cluster itself. Here is the code
clusterPool.js
var cluster = require('cluster');
exports.setupCluster = function(){
console.log ("Setting up cluster for bot processing " )
if (cluster.isMaster){
cluster.fork(); //one is good enough at the moment
}
}
compute.js
var async = require('async');
var clusterPool = require('.././clusterPool')
//Start the cluster
clusterPool.setupCluster();
exports.computeRealTime = function(req,res){
clusterPool.cluster.on("listening",function(worker){
//....Do something with the worker
})
}
webserver.js
// Include Express
var express = require('express');
var compute = require('.././compute');
// Create a new Express application
var app = express();
// Add a basic route – index page
app.get('/compute/real-time',compute.computeRealTime);
// Bind to a port
app.listen(3000);
Here is the error I am facing :
error: code=EADDRINUSE, errno=EADDRINUSE, syscall=bind
error: Error: bind EADDRINUSE
at errnoException (net.js:884:11)
at net.js:1056:26
at Object.1:2 (cluster.js:587:5)
at handleResponse (cluster.js:171:41)
at respond (cluster.js:192:5)
at handleMessage (cluster.js:202:5)
at process.EventEmitter.emit (events.js:117:20)
at handleMessage (child_process.js:318:10)
at child_process.js:392:7
at process.handleConversion.net.Native.got (child_process.js:91:7)
IS there any way out for this problem please?
Thanks in advance

This is one of the cases, when your server code faces an error and due to improper error handling, we get exception but the port is still busy. So you need to clear out the application which has reserved that port. If you are using linux, you can use
lsof -i :3000
Get the process id and kill that process using
kill -9 #processId
Then restart your server.

Related

How do you set up workers in a cluster using Node.js without having it in the same file?

I have this code in an index.js that I mostly left unmodified from the official Node.js documentation.
const https = require('https');
const fs = require('fs');
const cluster = require('node:cluster');
const numCPUs = require('node:os').cpus().length;
const process = require('node:process');
const livegame = require('./server-livegame');
const matchmaking = require('./server-matchmaking');
//Start ExpressJS
var express = require('express');
const { match } = require('assert');
var app = express();
app.use(express.json());
if (cluster.isPrimary) {
console.log(`Primary ${process.pid} is running`);
for (let i = 0; i< numCPUs; i++){
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
});
}
else
{
new livegame;
new matchmaking;
}
Here is a simplified code for livegame/matchmaking that produces the error.
const https = require('https');
const fs = require('fs');
const mongoose = require('mongoose');
//Import Models
const LiveMatch = require('./models/livematch');
//Start ExpressJS
var express = require('express');
const { match } = require('assert');
//Interface Security
var options = {
key: fs.readFileSync('key.pem', 'utf8'),
cert: fs.readFileSync('cert.pem', 'utf8')
};
//Server
var httpsServer = https.createServer(options, app);
httpsServer.listen(443);
var app = express();
app.use(express.json());
const chat =
{
puuid: String,
name: String,
roleID: String,
message: String,
}
app.post(':id/chat', (req,res) =>
{
//something here
});
I have livegame and matchmaking as separate .js files alongside the index.js whom I call to launch them programmatically as multiple instances. However, this is the error I get:
node:events:505
throw er; // Unhandled 'error' event
^
Error: listen EADDRINUSE: address already in use :::443
at Server.setupListenHandle [as _listen2] (node:net:1380:16)
at listenInCluster (node:net:1428:12)
at Server.listen (node:net:1516:7)
at C:\Users\----\Documents\MG\src\server-matchmaking.js:25:66
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Emitted 'error' event on Server instance at:
at emitErrorNT (node:net:1407:8)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
code: 'EADDRINUSE',
errno: -4091,
syscall: 'listen',
address: '::',
port: 443
}
Based on my progress so far, I think the issue is with me creating more "dining space" instead of hiring more "workers".
How do I properly create instances of a server with proper load balancing using clusters?
Clustering in nodejs, by its very definition is a group of processes that are all set up to process incoming connections the same. The master process uses an algorithm to rotate incoming connections among the various clustered processes so that each one gets a turn handling incoming connections. This is typically used when you need to increase the number of CPUs that you use for processing incoming http requests. By default a single nodejs process runs your Javascript in only a single thread/CPU.
And, by definition, these clustered processes are all doing the same thing (handling incoming http requests) as you are doing in the main process.
If, what you really want is to run different code (lets say you were going to do some heavy duty image processing) and you rightly want to get that heavy CPU processing out of main thread so it can remain responsive to incoming connections, then you would use either a WorkerThread (more threads in the same process) or a child_process (more processes). In both of those cases, you can run whatever code you want in the WorkerThread or child_process and it can be completely different than what you're doing in your main nodejs program.
If the underlying issue is some processing you're doing in a POST handler on your web server, then whether or not you need to investigate any of the above ways to scale depends entirely upon what you're doing in that POST handler. Nodejs by itself, with its asynchronous I/O model (for networking, file I/O, database access, etc...) can handle a ton of simultaneous requests without involving additional threads or processes. Properly written asynchronous code scales really well in nodejs.
So, unless your process is heavily using the CPU (as in the image processsing example I used above), then you should just write good asynchronous code first, see how that works and perhaps load test it to find where your bottlenecks are. You may indeed find that your bottlenecks are insigificant (thus you can get scale quite high) or they are not in a place that would benefit from the above additional processes and you need to attack the specific causes of the bottlenecks. With any high scale design, you first implement the basics, then instrument at scale to understand your bottlenecks, measure again, work on the bottlenecks, measure again, etc...
Guessing where your bottlenecks are is usually very error prone which causes you to put software engineering into the wrong places. Don't guess. Test, measure, find bottlenecks, work on bottlenecks. Rinse, lather, repeat.
Building on #krtee 's post:
The core problem here is that you're essentially trying to create multiple processes on the same port.
This is true, and you're really close to the node docs on this!
// essentially all this stuff
var httpsServer = https.createServer(options, app);
httpsServer.listen(443);
var app = express();
...
// needs to go in the `else` block of the worker initialization
...
for (let i = 0; i< numCPUs; i++){
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
});
}
else
{
// right bout here.
}
While I might not go with clustering, here is how I fixed this piece of code.
const https = require('https');
const fs = require('fs');
const cluster = require('node:cluster');
const numCPUs = require('node:os').cpus().length;
const process = require('node:process');
const livegame = require('./server-livegame');
const matchmaking = require('./server-matchmaking');
//Start ExpressJS
var express = require('express');
const { match } = require('assert');
var app = express();
app.use(express.json());
if (cluster.isPrimary) {
console.log(`Primary ${process.pid} is running`);
for (let i = 0; i< numCPUs; i++){
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
});
}
else
{
var httpsServer = https.createServer(options, app);
httpsServer.listen(443);
livegame(app);
matchmaking(app);
}
with livegame/matchmaking.js looking like
const https = require('https');
const fs = require('fs');
const mongoose = require('mongoose');
//Import Models
const LiveMatch = require('./models/livematch');
//Start ExpressJS
var express = require('express');
const { match } = require('assert');
this.serverLiveGame = function(app)
{
const chat =
{
puuid: String,
name: String,
roleID: String,
message: String,
}
app.post(':id/chat', (req,res) =>
{
});
};
module.exports = this.serverLiveGame;
There was more than one mistake in the code:
There can be only be one express() function handling the API for a given server. This value should be constant for any related APIs running under the same port. In my implementation, I simply pass the variable to the functions as a parameter.
To properly pass the api to the worker method from another .js, they must be passed on as a module with a proper module.exports. I wrapped the necessary code in a function so I only need to call one thing per api.
Since we are calling a function and not creating a new object, "new" is incorrect. We call it as any other function with function(param);
Thank you for all the help!

Node Segmentation Fault for any node command with very basic code

Why am I getting a segmentation fault error whenever I type in any node commands?
A bit of background information: I'm trying to deploy any basic demo node app (in GoDaddy's shared hosting) following these instructions (from the comment from user called 'x.g.'). I do everything and get to the very last instruction (number 5) where it states to type node app.js & and I get the following response in the terminal:
[1] 326516
If I type node app.js without the ampersand & I get this error:
Segmentation fault
Does anyone know why this happens and how to fix it? I basically have (as per the instructions) an app.js with this simple code:
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('NodeJS server running on Shared Hosting\n');
});
server.listen(port, hostname, () => {
console.log('Server running at http://${hostname}:${port}/');
});
Also, whenever I type anything like node, npm or node-v it also states the Segmentation fault error. Any help would be much appreciated!
Update: any ideas anyone?

'TypeError: Object is not a function' when using tunnel-ssh

I'm running the basic example in the tutorial for the popular NPM package tunnel-ssh. Here is the code:
var tunnel = require('tunnel-ssh');
var config = {
username:'root',
password:'secret',
host:'remote.mysql.server.com',
port:3306
}
tunnel(config, function(e, sshTunnel){
//Now, you should be able to connect to the tunnel via localhost:3336.
});
I am running it with the credentials for my own database of course. However, I always get this error when I run it:
TypeError: object is not a function
Anybody know what's going on?
var tunnel = require('tunnel-ssh');
var config = {username: 'vagrant',host: '192.168.33.2', port:3307, dstPort:3306 }
tunnel.tunnel(config, function(e, sshTunnel){});
I have my key added in 192.168.33.2 and forwarding the destination port 3306 to my local port 3307.
I am running this on RPEL node version v0.12.4. Its working.

"Object is not a function" when passing a Node.js HTTP server object to Socket.IO

This was working a few months ago when I was creating an HTTPS server, but I switched to http (not sure this switch is directly related, just mentioning it in case) today when revisiting this application, where I create a server and pass it to socket.io:
init.js
var server = require(dirPath + "/custom_modules/server").serve(80);
var socket = require(dirPath + "/custom_modules/socket").socket(server);
It is important that I pass the server to socket.io (I know there are alternate ways of initializing the socket) this way because that's how it has to be done in order to encrypt the websocket connection when I switch back to serving HTTPS later.
So my server module:
//serve files
module.exports.serve = function(port) {
//var server = https.createServer(options, function(req, res) { // SSL Disabled
var server = http.createServer(function(req, res) {
// Parse & process URL
var reqInfo = url.parse(req.url, true, true), path = reqInfo.pathname;
// Quickly handle preloaded requests
if (preloaded[path])
preloadReqHandler(req, res, preloaded[path], path);
// Handle general requests
else
generalReqHandler(req, res, reqInfo);
}).listen(port);
return server; //this should be returning an http server object for socket.io
};
and my socket module:
module.exports.socket = function(server) {
//create socket
var socket = require(dirPath + '/node_modules/socket.io')(server);
// ^ error
// .. snip ..
//handle client connection
socket.on("connection", function(client) {
// .. snip ..
});
};
and my error:
/home/ec2-user/Sales_Freak/server/custom_modules/socket.js:17
var socket = require(dirPath + '/node_modules/socket.io')(server);
^
TypeError: object is not a function
at Object.module.exports.socket (/home/ec2-user/Sales_Freak/server/custom_modules/socket.js:17:59)
at Object.<anonymous> (/home/ec2-user/Sales_Freak/server/init.js:16:59)
Assume all of the necessary Node.JS modules are required properly above. What silly mistake am I making today?
The exported module is not a function, refer to your previous statement:
var socket = require(dirPath + "/custom_modules/socket").socket(server);
And compare that to your current statement:
var socket = require(dirPath + '/node_modules/socket.io')(server);
I think you meant to do this instead.
var socket = require(dirPath + '/node_modules/socket.io').socket(server);
This might or might not be helpful to others, but my problem was that I changed the directory of my Node.js server files and socket.io wasn't installed in the new location.
The module was there in node_modules but not installed. I'm actually not sure how installation works with npm modules, but the module existed and therefore didnt throw an error saying it didnt exist, but did not act like it was really there until I did npm install socket.io
If you get this error in this situation, you forgot install socket.io.

How to use redis PUBLISH/SUBSCRIBE with nodejs to notify clients when data values change?

I'm writing an event-driven publish/subscribe application with NodeJS and Redis. I need an example of how to notify web clients when the data values in Redis change.
OLD only use a reference
Dependencies
uses express, socket.io, node_redis and last but not least the sample code from media fire.
Install node.js+npm(as non root)
First you should(if you have not done this yet) install node.js+npm in 30 seconds (the right way because you should NOT run npm as root):
echo 'export PATH=$HOME/local/bin:$PATH' >> ~/.bashrc
. ~/.bashrc
mkdir ~/local
mkdir ~/node-latest-install
cd ~/node-latest-install
curl http://nodejs.org/dist/node-latest.tar.gz | tar xz --strip-components=1
./configure --prefix=~/local
make install # ok, fine, this step probably takes more than 30 seconds...
curl http://npmjs.org/install.sh | sh
Install dependencies
After you installed node+npm you should install dependencies by issuing:
npm install express
npm install socket.io
npm install hiredis redis # hiredis to use c binding for redis => FAST :)
Download sample
You can download complete sample from mediafire.
Unzip package
unzip pbsb.zip # can also do via graphical interface if you prefer.
What's inside zip
./app.js
const PORT = 3000;
const HOST = 'localhost';
var express = require('express');
var app = module.exports = express.createServer();
app.use(express.staticProvider(__dirname + '/public'));
const redis = require('redis');
const client = redis.createClient();
const io = require('socket.io');
if (!module.parent) {
app.listen(PORT, HOST);
console.log("Express server listening on port %d", app.address().port)
const socket = io.listen(app);
socket.on('connection', function(client) {
const subscribe = redis.createClient();
subscribe.subscribe('pubsub'); // listen to messages from channel pubsub
subscribe.on("message", function(channel, message) {
client.send(message);
});
client.on('message', function(msg) {
});
client.on('disconnect', function() {
subscribe.quit();
});
});
}
./public/index.html
<html>
<head>
<title>PubSub</title>
<script src="/socket.io/socket.io.js"></script>
<script src="/javascripts/jquery-1.4.3.min.js"></script>
</head>
<body>
<div id="content"></div>
<script>
$(document).ready(function() {
var socket = new io.Socket('localhost', {port: 3000, rememberTransport: false/*, transports: ['xhr-polling']*/});
var content = $('#content');
socket.on('connect', function() {
});
socket.on('message', function(message){
content.prepend(message + '<br />');
}) ;
socket.on('disconnect', function() {
console.log('disconnected');
content.html("<b>Disconnected!</b>");
});
socket.connect();
});
</script>
</body>
</html>
Start server
cd pbsb
node app.js
Start browser
Best if you start google chrome(because of websockets support, but not necessary). Visit http://localhost:3000 to see sample(in the beginning you don't see anything but PubSub as title).
But on publish to channel pubsub you should see a message. Below we publish "Hello world!" to the browser.
From ./redis-cli
publish pubsub "Hello world!"
here's a simplified example without as many dependencies.
You do still need to npm install hiredis redis
The node JavaScript:
var redis = require("redis"),
client = redis.createClient();
client.subscribe("pubsub");
client.on("message", function(channel, message){
console.log(channel + ": " + message);
});
...put that in a pubsub.js file and run node pubsub.js
in redis-cli:
redis> publish pubsub "Hello Wonky!"
(integer) 1
which should display: pubsub: Hello Wonky! in the terminal running node!
Congrats!
Additional 4/23/2013: I also want to make note that when a client subscribes to a pub/sub channel it goes into subscriber mode and is limited to subscriber commands. You'll just need to create additional instances of redis clients. client1 = redis.createClient(), client2 = redis.createClient() so one can be in subscriber mode and the other can issue regular DB commands.
Complete Redis Pub/Sub Example (Real-time Chat using Hapi.js & Socket.io)
We were trying to understand Redis Publish/Subscribe ("Pub/Sub") and all the existing examples were either outdated, too simple or had no tests.
So we wrote a Complete Real-time Chat using Hapi.js + Socket.io + Redis Pub/Sub Example with End-to-End Tests!
https://github.com/dwyl/hapi-socketio-redis-chat-example
The Pub/Sub component is only a few lines of node.js code:
https://github.com/dwyl/hapi-socketio-redis-chat-example/blob/master/lib/chat.js#L33-L40
Rather than pasting it here (without any context) we encourage you to checkout/try the example.
We built it using Hapi.js but the chat.js file is de-coupled from Hapi and can easily be used with a basic node.js http server or express (etc.)
Handle redis errors to stop nodejs from exiting. You can do this by writing;
subcribe.on("error", function(){
//Deal with error
})
I think you get the exception because you are using the same client which is subscribed to publish messages. Create a separate client for publishing messages and that could solve your problem.
Check out acani-node on GitHub, especially the file acani-node-server.js. If these links are broken, look for acani-chat-server among acani's GitHub public repositories.
If you want to get this working with socket.io 0.7 AND an external webserver you need to change (besides the staticProvider -> static issue):
a) provide the domain name instead of localhost (i.e. var socket = io.connect('http://my.domain.com:3000'); ) in the index.html
b) change HOST in app.js (i.e. const HOST = 'my.domain.com'; )
c) and add sockets in line 37 of app.js (i.e. 'socket.sockets.on('connection', function(client) { …' )
Update to the code:
staticProvider
now renamed to
static
see migration guide
according to #alex solution. if you have an error like this one as per #tyler mention:
node.js:134
throw e; // process.nextTick error, or 'error'
event on first tick ^ Error: Redis connection to 127.0.0.1:6379 failed - ECONNREFUSED, Connection refused at Socket.
then you need to install Redis first. check this out:
http://redis.io/download

Categories