Anyone know how to run Node Cluster on windows? I haven't been able to find any articles on the web and cannot seem to solve this problem:
events.js:160
throw er; // Unhandled 'error' event
^
Error: write ENOTSUP
at exports._errnoException (util.js:1007:11)
at ChildProcess.target._send (internal/child_process.js:634:20)
at ChildProcess.target.send (internal/child_process.js:521:19)
at sendHelper (cluster.js:751:15)
at send (cluster.js:534:12)
at cluster.js:509:7
at SharedHandle.add (cluster.js:99:3)
at queryServer (cluster.js:501:12)
at Worker.onmessage (cluster.js:449:7)
at ChildProcess.<anonymous> (cluster.js:765:8)
And the code...
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('online', (worker) => {
console.log('Worker ' + worker.process.pid + ' is online');
});
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died with code ${code} and signal ${signal}`);
});
} else {
console.log('else part ');
openPort();
}
function openPort() {
let server = dgram.createSocket('udp4');
server.bind(port, host);
server.on('message', processMessage);
}
Support for UDP clustering was added in v0.11.14 (for Linux and OSX).
Check file on node.js master, which says "dgram clustering is currently not supported on windows"
In the current node js version I am using below code to create cluster on windows.
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', function(worker, code, signal) {
console.log("worker ${worker.process.pid} died");
cluster.fork();
});
} else {
var express = require('express');
var http = require('http');
// init app
var app = express();
function createServer(app) {
return http.createServer(app);
}
app.locals.server = createServer(app);
app.locals.server.listen(port, function() {
console.info("server online");
});
}
This will create clusters on same port.
So, in order to use UDP with Node cluster on Windows, you have to call server.bind like this:
server.bind({port: 1900, exclusive: true}, function () {
console.log('PORT BIND SUCCESS');
server.setBroadcast(true);
server.setMulticastTTL(128);
server.addMembership(multicastAddress, myIp);
});
The key part is to pass in the object {port: PORT, exclusive: true} to the bind function. I found the answer here: https://github.com/misterdjules/node/commit/1a87a95d3d7ccc67fd74145c6f6714186e56f571
Related
i try to implement cluster in my node app with socket.io. if i not using cluster everything is working good. but when i use cluster its occur following error in client browser.
WebSocket connection to 'ws://localhost:8000/socket.io/?EIO=3&transport=websocket&sid=Ff8LkaCbF5g92lKOAAAS' failed: Error during WebSocket
socket.js:2 POST http://localhost:8000/socket.io/?EIO=3&transport=polling&t=MAjySbD&sid=Ff8LkaCbF5g92lKOAAAS 400 (Bad Request)
here is server.js
var http = require('http');
var app = require('../app');
cluster = module.exports = require('cluster');
const numCPUs = require('os').cpus().length;
var server = http.createServer(app);
io = module.exports = require('socket.io').listen(server, {
pingTimeout: 7000,
pingInterval: 10000
});
io.set("transports", ["xhr-polling","websocket","polling"]);
if(cluster.isMaster){
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else {
var port = 8000;
var host = '0.0.0.0';
server.listen(port,host,function(){
log('server is running on ' + host +':'+port);
});
}
here is the client.js
var socket = io.connect('http://localhost:8000/dashboard',{transports: ['websocket']});
Check if you using express-status-monitor as a middleware on express, this makes http call on the first (request) handshake of WebSocket goes failed, or maybe another factor like proxy (nginx) or similar like that
Look here for more details about this error
I am learning clustering in NodeJS. I have two tasks one is node-sass and another one is uglifyjs which I want to run by two different workers using cluster in nodeJS. Though the code is working file and creating the SASS -> CSS file and main.js to main.min.js file.
But I am not sure whether it is handled by separate workers or not. Let me know where I can make the amendments to make -
SASS -> CSS handled by one worker
UglifyJS task by second worker
Once both tasks complete Master console a successful message
Following is my code:
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
var fs = require('fs');
var UglifyJS = require("uglify-js");
var sass = require('node-sass');
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
// Fork workers.
for (let i = 0; i < 2; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else {
var result = UglifyJS.minify("js/main.js");
fs.writeFile(__dirname + '/js/main.min.js', result.code, function(err){
if(err)
throw err;
});
sass.render({
file: './css/main.scss',
outFile: 'css',
}, function(err, result) {
if(err)
throw err;
fs.writeFile(__dirname + '/css/main.css', result.css, function(err){
if(err)
throw err;
});
});
console.log(`Worker ${process.pid} started`);
}
I think this will help
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
var fs = require('fs');
var UglifyJS = require("uglify-js");
var sass = require('node-sass');
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
cluster.fork()
.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
cluster.fork()
.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else if (cluster.worker.id === 1) {
console.log(`Worker ${process.pid} started`);
sass.render({
file: './css/main.scss',
outFile: 'css',
}, function (err, result) {
if (err)
throw err;
fs.writeFile(__dirname + '/css/main.css', result.css, function (err) {
if (err)
throw err;
});
});
process.exit();
} else {
var result = UglifyJS.minify("js/main.js");
fs.writeFile(__dirname + '/js/main.min.js', result.code, function (err) {
if (err)
throw err;
});
process.exit();
}
In the cluster --> master-slave scenarios the real basic code, as in many parts of the original Node.js structure, is sometimes a bit more complicated than just declaring a master and slave. Here is one of the cases where I would strongly advise a couple of hours searching NPM and finding a module that will work for your schema. I have tested cluster-master but in your case you may actually need more than one NPM module. It would be well to keep in mind that clusters usually mean cores where you are going to fork -- above code cluster.fork();.
You want to implement the cluster master-worker paradigm correctly and you want a return from each worker and know the process is running as you think it should. Either that means delving deep into the Node.js cluster documentation and implementation, or researching the various NPM modules available which will usually obfuscate the hard work for you.
For poc part I tried node cluster and pm2, pm2 looks very easy to setup. pm2 also can keep the node project running in background.
Add pm2 command in your build script or just try this and see how it works
pm2 start app.js -i max
Refer
http://pm2.keymetrics.io/docs/usage/cluster-mode/
Using the cluster module in node I can allow for a http server to run on multiple cores, increasing concurrency, which is great. But if my app contains other tasks which I do not want to run multiple times, such as a scheduled event. How can I do this?
My basic code using the cluster module is like so...
var cluster = require('cluster');
if(cluster.isMaster){
var numWorkers = require('os').cpus().length;
for(var i = 0; i < numWorkers; i++) {
cluster.fork();
}
//restart dead workers
cluster.on('exit', function(worker, code, signal) {
console.log('Worker ' + worker.process.pid + ' died with code: ' + code + ', and signal: ' + signal);
console.log('Starting a new worker');
cluster.fork();
});
}else{
var http = require('http');
var server = http.createServer(function(req, res) {
res.write(process.pid.toString());
res.end();
});
server.listen(5000);
console.log("Server is listening");
}
Now if I have a task that I want to run every hour like.
setInterval(function(){
doSomething();
}, 60*60*1000);
Where would I put it? I have read that the master should only manage workers, to avoid any risk of the master throwing an error and crashing. Is it possible to give individual events to specific workers maybe?
I fork workers in my Node.js application via the Cluster module and pass a custom ID to the environment of all my workers. That works well for far.
However, I do not know how I can access this id in my master when an 'online' or 'exit' event is emitted.
The documentation is not very helpful. Could you please point me the right way?
var cluster = require('cluster');
if (cluster.isMaster) {
//MASTER
function fork() {
var worker_env = {worker_id:'my_custom_id'};
cluster.fork(worker_env);
}
cluster.on('online', function(worker) {
console.log(worker.process.env.worker_id); // undefined
//
// How can I access my custom worker id here?
//
});
cluster.on('exit', function(worker, code, signal) {
//
// And here...?
//
fork();
});
} else {
// WORKER
console.log(process.env.worker_id); // my_custom_id
}
theres no way, the worker process env is not exposed to the master.
One aproach can be a map of our cluster (a object containig the needed info).
Something like these:
var cluster = require('cluster');
if (true === cluster.isMaster) {
//CODE EXECUTED BY MASTER
var cluster_map = {}; // Here we store the workers info in a object
var restart_Limit = 10; // max global worker restart (10)
function fork_worker(myWorkerId) {
// these makes worker_id available in the worker
var worker = cluster.fork({
worker_id: myWorkerId
});
// max restarts limit (global)
if (worker.id >= restart_Limit) {
console.log('Restart limit reached, bye!');
process.kill();
}
// here we add the key "myWorkerId" to the cluster map
cluster_map[worker.id] = myWorkerId;
// WORKER AUTO-KILL
setTimeout(function() {
console.log('stoping...' + myWorkerId);
worker.kill();
}, 3000);
}
cluster.on('online', function(worker) {
var online_proc = cluster_map[worker.id];
console.log('worker online: ' + online_proc + '\n Restarts: ' + worker.id);
});
cluster.on('exit', function(worker, code, signal) {
var exited_proc = cluster_map[worker.id];
// delete the process from the cluster map
delete cluster_map[worker.id];
console.log("worker offline: " + exited_proc);
// WORKER AUTO-RESTART
setTimeout(function() {
console.log('Restarting... ' + exited_proc);
fork_worker(exited_proc);
}, 3000);
});
// start the magic ( 3 workers )
(function() {
fork_worker('id_1');
fork_worker('id_2');
fork_worker('id_3');
})();
} else {
//CODE EXECUTED BY EACH WORKER (process env is present here).
console.log('hi from the worker, process.env: ' + process.env.worker_id);
// all the hard work for the workers here.
}
I'm trying to implement a message queue using node, socket.io, and redis. I am attempting to follow the reliable queue pattern outlined Here. I am trying to read a logfile (60M in size) in line-by-line (will be changing this later) and pump the lines into the queue for processing later. However, I am running into a memory allocation issue. I'm not sure how to troubleshoot this and would like some guidance on where to start. I can't tell if the issue is in reading the file, or in the redis client. I have been able to add messages to the queue one by one like this :
socket.emit('message', 'some sort of log line here');
Therefore I know the listener is working, but when I run the socketClient.js file It will spin out for a bit and then ultimately fail with the following generic error message:
FATAL ERROR: JS Allocation failed - process out of memory
Is there some error handling, or profiling I can add to get more information on where this is failing?
Here is the code:
socketListener.js
var util = require("util"),
redis = require("redis"),
io = require('socket.io').listen(8088)
client = redis.createClient("7777", "localhost");
util.log("Established connection to redis");
io.sockets.on('connection', function(socket) {
util.log("socket connection established for socket : " + socket);
socket.on('message', function (data) {
util.log("received the following data : ");
util.log(JSON.stringify(data, 0, 3));
client.on("error", function(err) {
util.log("Error " + err);
});
try {
// reliable queue pattern implementation
util.log("queuing up the data in the list");
client.rpush('logList', data);
client.brpoplpush('logList', 'dequeueList', 10);
} catch (err) {
util.log("An error occurred : ");
util.log(JSON.stringify(err, 0, 3));
}
});
socket.on('disconnect', function() {});
});
socketClient.js
var io = require("socket.io-client");
var socket = io.connect('http://localhost:8088');
var redis = require('redis');
var util = require('util');
var fs = require('fs');
var readline = require('readline');
socket.on('connect', function() {
client = redis.createClient("7777", "localhost");
var rd = readline.createInterface({
input: fs.createReadStream('someLogFile.log'),
terminal: false
});
rd.on('line', function(line) {
util.log("reading line " + line);
socket.emit('message', line);
});
client.lrange('dequeueList', 0, -1, function(err, results) {
if (err) {
util.log(err);
} else {
var multi = client.multi();
for (var i=0; i < results.length; i++) {
util.log('got : ' + results[i]);
multi.hgetall(results[i]);
}
multi.exec(function(err, logs) {
util.log("executing the multi commands");
util.log(JSON.stringify(logs, 0 ,3));
})
};
});
})
Thank you in advance for the help!