Prevent multiple console logging output while clustering - node.js

I'm using the cluster module for nodejs.
Here is how I have it set up:
var cluster = require('cluster');
if (cluster.isMaster) {
var numCPUs = require('os').cpus().length;
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
}else{
console.log("Turkey Test");
}
Now, I am forking 6 threads (6 cores) on my PC. So, when debugging my app and reading data from the console, this will appear:
Is there anyway to make console.log output only once regardless of how many clusters are running?

You could use the fact that you can communicate with the workers, and send a message that tells each worker if it should log or not. You'd send it so that only one worker (The first one for example) should log:
var cluster = require('cluster');
if (cluster.isMaster) {
var numCPUs = require('os').cpus().length;
for (var i = 0; i < numCPUs; i++) {
cluster.fork().send({doLog: i == 0});
}
}else{
process.on('message', function(msg) {
if(msg.doLog) {
console.log('Turkey Test');
}
});
}

Related

Node.js Cluster not forking anything

I am trying to implement clustering in my Node.js application.
When I print out how many workers are spawned inside the for-loop with the fork() method, it prints out nothing.
The coreCounter variable also = 0 if I print it out.
Here is my code:
let cluster = require('cluster');
if (cluster.isMaster) {
let coreCounter = require('os').cpus.length;
for (let i = 0; i < coreCounter; i++) {
cluster.fork();
}
cluster.on('exit', function () {
cluster.fork();
});
} else {
require('server.js');
}
I tried to npm install cluster and npm install os, it did not work, do I have to do npm install if I "require" something?
You just need to add () after the cpus.
See here:
let cluster = require('cluster');
if (cluster.isMaster) {
let coreCounter = require('os').cpus().length;
for (let i = 0; i < coreCounter; i++) {
cluster.fork();
}
cluster.on('exit', function () {
cluster.fork();
});
} else {
//require('server.js');
console.log('walla!')
}
You should not npm install NodeJS core modules.
P.S. I suggest you get some practice with NodeJS before implement clustering

NodeJS Cluster how share object array across workers

So I have setup a simple nodejs cluster game, I am new to nodejs. basically players connect to to my worker using socket.io then they get created to a Player Object then added to my PlayerManager.LIST array. Now this causes me some issues as the PlayerManager.LIST is on each of workers and are not sync'd.
So my question is, is there a better way of doing this so that if I connect to worker 2 I see same player list as worker 1's.
Structure at the moment:
app.js
-> worker
->-> PlayerManager (Contains List)
->->-> Player
Git Repo: https://github.com/mrhid6/game_app_v2
NodeJS Clusters are based on Nodejs Child Processes. In child processes you can send data between parent (Master in cluster) and child (worker in cluster) via messages over IPC channel. You can do the same with clusters using message events
var cluster = require('cluster');
var _ = require('lodash');
var http = require('http');
var workers = [];
var workerCount = 4;
if (cluster.isMaster) {
for (var i = 0; i < workerCount; i++) {
var worker = cluster.fork();
worker.on('message', function(msg) {
if (msg.task === 'sync') {
syncPlayerList(msg.data);
}
});
}
workers.push[worker];
} else {
var worker = new Worker();
process.on('message', function(msg) {
if (msg.task === 'sync') {
worker.playerList = msg.data;
}
});
}
function syncPlayerList (playerList) {
_.forEach(workers, function (worker) {
worker.send({
task: 'sync',
data: playerList
});
});
};
// worker class
function Worker() {
this.playerList = [];
}
Worker.prototype.sendSyncEvent = function () {
process.send({
task: 'sync',
data: this.playerList
})
};

ZeroMQ: How to notify a Publisher from a Subscriber

I use PUB/SUB ZeroMQ pattern.
System consists from Web Server ( Publisher ), clustered TCP servers ( Subscribers ) and external applications ( clients, which connect to TCP servers ).
Huge amount of external clients connect to every TCP server. Every external client has unique peerId which I use as topic in Publisher. For some management purposes I send messages to TCP servers ( like remove peer, change, etc. ). But also I need to send messages from TCP server to Web Server ( connect, disconnect, error ). I didn't find right way how to do it. Can anybody suggest how to do it correctly?
Update 1
It looks like using ROUTER/DEALER pattern is the most convenient for that.
Some comments about scripts.
External clients connect to tcp servers ( cluster ) and send unique peerId, on tcp server side tcp socket cached by unique peerId. Then tcp server sends peerId message by ZeroMQ socket to Web Server. Web Server caches envelope by peerId. Every n milliseconds Web Server sends messages to random peer ( generate 'peerId' ). TCP Server receives these messages, gets correct tcp socket from cache and sends theirs to clients. Clients calculate count of messages and every n milliseconds send their to TCP server, which sends count to WEB Server by ZeroMQ socket. On Web Server every n milliseconds count of sended and received messages are printed on console.
Test js script of server part:
var cluster = require('cluster'),
zmq = require('zmq'),
net = require('net'),
zmqport = 'tcp://127.0.0.1:12345';
var count = 10;
var countPeers = 10000;
var interval = 1;
if (cluster.isMaster) {
for (var i = 0; i < count; i++) cluster.fork({
TCP_SERVER: 1
});
cluster.fork({
WEB_SERVER: 1
});
cluster.on('death', function (worker) {
console.log('worker ' + worker.pid + ' died');
});
} else {
if (process.env.TCP_SERVER) {
var sockets = Object.create(null);
var socket = zmq.socket('dealer');
socket.identity = 'process-' + process.pid;
socket.connect(zmqport);
socket.on('message', function (peerIdBuffer) {
var peerId = peerIdBuffer.toString();
if (typeof sockets[peerId] !== 'undefined') {
var buffer = new Buffer(4);
buffer.writeUInt32BE(1, 0);
sockets[peerId].write(buffer);
}
});
var server = net.createServer(function (tcpsocket) {
tcpsocket.on('data', function (data) {
if (!tcpsocket.peerId) {
var peerId = data.toString();
sockets[peerId] = tcpsocket;
tcpsocket.peerId = peerId;
return socket.send(['id', data]);
}
return socket.send(['count', data]);
});
});
server.listen('13333', '0.0.0.0');
} else {
var countMessagesSended = 0;
var countMessagesReceived = 0;
var socket = zmq.socket('router');
var clients = Object.create(null);
socket.bind(zmqport, function (err) {
if (err) throw err;
setInterval(function () {
for (var i = 0; i < countPeers; i++) {
var topic = Math.floor(Math.random() * countPeers) + '-peer';
if (typeof clients[topic] !== 'undefined') {
countMessagesSended++;
socket.send([clients[topic], topic]);
}
}
}, interval);
});
socket.on('message', function (envelope, messageId, data) {
switch (messageId.toString()) {
case "id":
clients[data.toString()] = envelope.toString();
break;
case "count":
countMessagesReceived += data.readUInt32BE(0);
break;
}
});
setInterval(function () {
console.log('%s messages have been sended, %s - received', countMessagesSended, countMessagesReceived);
countMessagesSended = 0;
countMessagesReceived = 0;
}, 5000);
}
}
Test js script for clients:
var cluster = require('cluster'),
net = require('net');
var count = 10;
if (cluster.isMaster) {
for (var i = 0; i < count; i++) cluster.fork({
CLUSTER: i
});
cluster.on('death', function (worker) {
console.log('worker ' + worker.pid + ' died');
});
} else {
var clientspernode = 1000;
var offset = parseInt(process.env.CLUSTER, 10);
for (var j = (offset) * clientspernode; j < (offset + 1) * clientspernode; j++) {
(function (j) {
var countMessages = 0;
var client = net.connect({
port: 13333,
host: '127.0.0.1'
}, function () {
client.write(j + '-peer');
});
client.on('data', function (buffer) {
countMessages += Math.ceil(buffer.length / 8);
});
client.on('error', function () {
});
setInterval(function () {
var buf = new Buffer(4);
buf.writeUInt32BE(countMessages, 0);
client.write(buf);
countMessages = 0;
}, 5000);
})(j);
}
}

Cluster in nodejs

I have tried the below piece of code in ubuntu
var cluster = exports.cluster = require('cluster');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', function(worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died. Trying to respawn...');
cluster.fork();
});
} else {
//spawn express etc
}
How can I check the CPU performance in ubuntu with or without using cluster in nodejs.
Any help on this will be really helpful

node.js fork function and passing arguments to child-process

I pass arguments when create chlid-processes
if (cluster.isMaster) {
for (var i = 0; i < os.cpus().length; i++) {
var new_worker_env = {};
new_worker_env["WORKER_NAME"] = "worker" + i;
var new_worker = cluster.fork(new_worker_env);
}
}
and then try to read it in childs:
if ( process.env["WORKER_NAME"] != undefined ) instance.name = process.env["WORKER_NAME"];
but this var isn't exist, why?
Node v0.8.8
Seems to work for me on Windows, Node.js version 0.8.8
var cluster = require('cluster'),
os = require('os');
if (cluster.isMaster) {
for (var i = 0; i < os.cpus().length; i++) {
var new_worker_env = {};
new_worker_env["WORKER_NAME"] = "worker" + i;
var new_worker = cluster.fork(new_worker_env);
}
} else {
console.log(process.env['WORKER_NAME']);
}
outputs:
worker0
worker1

Resources