Cron Job running multiple times under cluster environment in Node js - node.js

i have set up Node JS server cluster environment to fully utilize all the cores of my server. There is a Cron Job which runs every day 08 O'clock to run some tasks. But due to clustering it runs 4 times(server is of 4 cores) every day at 08 O'clock.
How can i over come this problem to run Cron Job only once a day?
if(cluster.isMaster) {
var numWorkers = require('os').cpus().length;
console.log('Master cluster setting up ' + numWorkers + ' workers...');
for(var i = 0; i < numWorkers; i++) {
cluster.fork();
}
cluster.on('exit', function(worker, code, signal) {
console.log('Worker ' + worker.process.pid + ' died with code: ' + code + ', and signal: ' + signal);
cluster.fork();
});
} else {
var CronJob = require('cron').CronJob;
new CronJob('01 30 08 * * 0-6', function() {
console.log('Running Schedular');
//Performing tasks
}, null, true, 'America/Los_Angeles');
var server = app.listen(port, function() {
console.log('Process ' + process.pid + ' is listening to all incoming requests');
});
}

Hi Please find the below changes, I just changed cron job into if condition.
var CronJob = require('cron').CronJob;
if(cluster.isMaster) {
var numWorkers = require('os').cpus().length;
console.log('Master cluster setting up ' + numWorkers + ' workers...');
for(var i = 0; i < numWorkers; i++) {
cluster.fork();
}
cluster.on('exit', function(worker, code, signal) {
console.log('Worker ' + worker.process.pid + ' died with code: ' + code + ', and signal: ' + signal);
cluster.fork();
});
new CronJob('01 30 08 * * 0-6', function() {
console.log('Running Schedular');
//Performing tasks
}, null, true, 'America/Los_Angeles');
} else {
var server = app.listen(port, function() {
console.log('Process ' + process.pid + ' is listening to all incoming requests');
});
}

Let the master cluster handle the cron job and not one of the worker threads.

Related

Agenda.js preventing app.js working

I'm trying to add in Agenda into my node application so I can run some background tasks on a daily basis, e.g. Deactivating users who have not logged in for 60 days.
I've tried following the example on the GitHub associated with the module, but seem to be running into a problem with my app hanging whenever I try to load the site, and ultimately getting an "Error 504: Gateway Server Timeout". I'm also seeing undefined in the console.
I know Agenda is up and working correctly, as I have a simple job at the moment that just does a console.log every minute.
In my app.js I require my worker.js file:
var agenda = require('./worker.js');
My worker.js is just a simple 1 line:
require('./lib/agenda.js');
agenda.js:
var Agenda = require('agenda');
var connectionString = "mongodb://" + process.env.MONGODB_USER + ":" +
process.env.MONGODB_PASSWORD + "#" +
process.env.DATABASE_SERVICE_NAME + ':' +
process.env.MONGODB_PORT + '/' +
process.env.MONGODB_DATABASE;
var agenda = new Agenda({db: {address: connectionString}});
var jobTypes = process.env.JOB_TYPES ? process.env.JOB_TYPES.split(',') : [];
jobTypes.forEach(function(type){
require('./jobs/' + type)(agenda);
});
if (jobTypes.length) {
agenda.on('ready', function() {
agenda.every('* * * * *', 'test job') //Run job at 0030 every day
agenda.start();
})
}
module.exports = agenda
and the test job is defined in a job file like so:
agenda.define('test job', function(job, done) {
console.log ('Agenda job executed');
done();
});
I feel like I am missing something really obvious!
It turns out that I needed to add an agenda.processEvery in the start command section of my agenda.js:
var Agenda = require('agenda');
var connectionString = "mongodb://" + process.env.MONGODB_USER + ":" +
process.env.MONGODB_PASSWORD + "#" +
process.env.DATABASE_SERVICE_NAME + ':' +
process.env.MONGODB_PORT + '/' +
process.env.MONGODB_DATABASE;
var agenda = new Agenda({db: {address: connectionString}});
var jobTypes = process.env.JOB_TYPES ? process.env.JOB_TYPES.split(',') : [];
jobTypes.forEach(function(type){
require('./jobs/' + type)(agenda);
});
if (jobTypes.length) {
agenda.on('ready', function() {
agenda.every('* * * * *', 'test job') //Run job at 0030 every day
agenda.processEvery('one minute'); //<====== This is the new line
agenda.start();
})
}
module.exports = agenda

Node.js: Limit forks in cluster

I have a Web application and an application that runs in background, this last load much the server, so far has been working properly, but in the last version to add new features, carries a lot of load and blocks the server.
I have been trying to modify the code that runs the cluster, but always load the same number of processes.
This is my code:
var cluster = require('cluster'),
limitWorkers = Math.ceil(require('os').cpus().length / 2),
jobWorkers = [],
webWorkers = [];
if(cluster.isMaster) {
//let limit = 0;
require('os').cpus().forEach(function() {
addWebWorker();
/*if(limit < limitWorkers) {
limit++;
addJobWorker();
}*/
if( limitWorkers > 0 ) {
--limitWorkers;
addJobWorker();
}
});
cluster.on('exit', function(worker, code, signal) {
if (jobWorkers.indexOf(worker.id) != -1) {
console.log('job worker ' + worker.process.pid + ' died. Trying to respawn...');
removeJobWorker(worker.id);
addJobWorker();
}
if (webWorkers.indexOf(worker.id) != -1) {
console.log('http worker ' + worker.process.pid + ' died. Trying to respawn...');
removeWebWorker(worker.id);
addWebWorker();
}
});
} else {
console.log('start http server: ' + cluster.worker.id);
require('./apps/web-http'); //initialize the http server here
//if( process.env.job === 1 ){
if( jobWorkers.indexOf(cluster.worker.id) != 1 ) {
//if( limitWorkers > 0 ) {
//limitWorkers--;
console.log('start job server: ' + cluster.worker.id);
require('./apps/jobs-worker'); //initialize the job here
//}
}
}
function addWebWorker() {
webWorkers.push(cluster.fork({web: 1}).id);
}
function addJobWorker() {
jobWorkers.push(cluster.fork({job: 1}).id);
}
function removeWebWorker(id) {
webWorkers.splice(webWorkers.indexOf(id), 1);
}
function removeJobWorker(id) {
jobWorkers.splice(jobWorkers.indexOf(id), 1);
}
Any idea to run the job worker half the cores of the processor or just one? Thanks.

Move Node.js TCP server from localhost to VPS (Openshift)

I have a working node.js server when it runs on localhost, i can send and receive data from my client (written in java). However, when i move the server.js to the VPS application at Openshift (free) the client can no longer connect to the server.js.
I've uploaded the files as instructed, I open a SSH connection via terminal to server, navigate to the repo folder (where uploaded files is), run "node server.js" (it appears to be online, no error and the on.('online',..) events activates.
And when i then run the client on my computer it isn't able to connect to the server.js.
server.js:
var os = require('os');
var HOST = process.env.OPENSHIFT_NODEJS_IP;;
var PORT = process.env.PORT || 80;
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
var net = require('net');
console.log("Hostname: " + HOST + "\nPort: " + PORT);
if (cluster.isMaster) {
cluster.SCHED_RR;
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
Object.keys(cluster.workers).forEach(function(id){
console.log("I am runnong with ID: " + cluster.workers[id].process.pid);
});
console.log('\n');
cluster.on('online', function(worker) {
console.log('Worker: ' + worker.process.pid + " listning on port " + PORT);
});
cluster.on('exit', function(worker, code, signal){
console.log("Worker " + worker.process.pid + " died")
});
} else {
// Load the TCP Library
net = require('net');
// Keep track of the chat clients
var clients = [];
// Start a TCP Server
var server = net.createServer(function (socket) {
console.log('\n');
// Identify this client
socket.name = socket.remoteAddress + ":" + socket.remotePort
// Put this new client in the list
clients.push(socket);
// Send a nice welcome message and announce
socket.write("Welcome " + socket.name + "\n\n");
broadcast(socket.name + " joined the chat\n", socket);
// Handle incoming messages from clients.
socket.on('data', function (data) {
//var ls = net.connect(5001, 'localhost');
var string = data + "";
//console.log(string);
var message = string.split("|");
broadcast(" Passing data from "+message[2]+" to "+message[1] + "\n " + message[3], socket);
//ls.write(string);
//ls.end();
});
socket.on('connect', function(){
broadcast("\n New connection opened.\n");
});
// Remove the client from the list when it leaves
socket.on('end', function () {
clients.splice(clients.indexOf(socket), 1);
broadcast("\n" + socket.name + " left the chat.\n");
});
// Send a message to all clients
function broadcast(message, sender) {
clients.forEach(function (client) {
// Don't want to send it to sender
if (client === sender) return;
client.write(message);
});
// Log it to the server output too
process.stdout.write(message)
}
})
server.listen(PORT, HOST);
server.on('error', function (e) {
if (e.code == 'EADDRINUSE') {
console.log('Address in use, retrying...');
setTimeout(function () {
server.close();
server.listen(PORT, HOST);
}, 1000);
}
else if (e.code == 'ECONNREFUSED') {
console.log('Connection refused');
}
});
}
Client.java (relevant parts)
public static void main(String args[]) {
String s = getPackage();
try {
System.out.print("\n");
/*InetAddress addr;
Socket sock = new Socket("ex-std-node272.prod.rhcloud.com", 80);
addr = sock.getInetAddress();
System.out.println("Connected to " + addr);*/
Socket skt = new Socket("127.10.100.1", 80);
BufferedReader inStream = new BufferedReader(new
InputStreamReader(skt.getInputStream()));
DataOutputStream outStream = new DataOutputStream(skt.getOutputStream());
//System.out.print(" Received string: '");
//while (!inStream.ready()) {}
//System.out.print(inStream.readLine()); // Read one line and output it
System.out.print("'\n\n");
// Send first message
//outStream.writeByte(1);
outStream.writeUTF(s);
//outStream.flush(); // Send off the data
//outStream.write(b,0,b.length);
outStream.flush(); // Send off the data
}
catch(Exception e) {
System.out.print(" Error: " + e);
}
}
When i run the server.js (at the VPS) it gives me the Hostname: 127.10.100.1 and Port: 80 which i've then pasted into the client.
So, what do i need to do with the code i have to make it connect?
You need to listen on port 8080, not port 80. Try reading over this section of the Developer Center on Port Binding: https://developers.openshift.com/en/managing-port-binding-routing.html
The first thing to note is that PORT in your server.js should be made equal to process.env.OPENSHIFT_NODEJS_PORT or 8080 as Corey already mentioned.
The second problem is that when you run your client on your local machine, the host you should be connecting to the URL given to your application when you created it something like http://<appname>-<domain>.rhcloud.com. You can see your application url when you issue the command:
rhc show-app <appname>

How to make a node.js application keep listening after closing a socket?

I'm trying to set up a node.js application that could receive connections and still be listening to port 9001 once a socket is ended. How can I do that? Here is my current code (it doesn't close after the socket.end(), but it won't accept any other connections) :
var net = require('net');
var mySocket;
var server = net.createServer(function(socket) {
mySocket = socket;
mySocket.on("connect", onConnect);
mySocket.on("data", onData);
});
function onConnect() {
console.log("Connected");
}
function onData(command) {
if (command == "exit") {
console.log("Exiting");
mySocket.end();
}
}
console.log("Waiting for incoming connections");
server.listen(9001);
I tried to add another server.listen(9001); after the socket.end();, but I get a : Error: listen EADDRINUSE message.
Also, will that code be able to receive several connections coming from different addresses at the same time, and handle them separately?
This is the full code. When executed, node.js receives 4 commands from the Flash application, and works properly (except that the onConnect() function seems never to be called), and the "exit;" command closes the socket properly, yet if I reload the Flash application, it doesn't connect to the server
var net = require('net');
const PACKET_SEPARATOR = 59 // ;
var connection_ack = false;
var counter = 0;
var server = net.createServer(function(socket) {
function onConnect() {
console.log("Connected to Flash");
}
function dataHandler(command) {
if (command[command.length - 1] != String.fromCharCode(PACKET_SEPARATOR) && connection_ack) {
console.log("SEP : " + PACKET_SEPARATOR + " - last : " + command[command.length - 1] + " - ack " + connection_ack);
console.log("CAUGHT EXCEPTION : WRONG PACKET FORMAT --- " + command + " --- " + command.length);
}
if (command == "exit;") {
console.log("Received exit request from " + socket.address().address + ":" + socket.address().port + " (" + socket.address().family + "). Ending connection...");
socket.end();
}
else if (command == "<policy-file-request/>\0") {
socket.write('<cross-domain-policy>\n<allow-access-from domain="*" to-ports="*" />\n</cross-domain-policy>\0', 'utf8');
console.log("Policy file sent to " + socket.address().address + ":" + socket.address().port);
player1.pxacceleration = 0;
player1.pyacceleration = 0;
connection_ack = true;
}
else {
console.log("Got data from " + socket.address().address + ":" + socket.address().port + " (" + socket.address().family + ")");
console.log("--> " + command);
counter++;
socket.write("Received " + counter + " commands;", 'utf8');
console.log("Sending : Received " + counter + " commands;");
}
}
function onData(d) {
var command = "";
for (i=0; i <= d.length - 1; i++) {
command += String.fromCharCode(d[i]);
if (d[i] == PACKET_SEPARATOR || i == d.length - 1 && !connection_ack) {
dataHandler(command);
command = "";
}
}
}
socket.on("connect", onConnect);
socket.on("data", onData);
});
console.log("Ready. Waiting for incoming connections");
server.listen(9001);
server.listen(80); //TODO : Remove?
As jfriend00 said, using mySocket as a global is not recommended. Try the below instead.
var server = net.createServer(function(socket) {
function onData(command) {
if (command == "exit") {
console.log("Exiting");
socket.end();
}
}
socket.on("connect", onConnect);
socket.on("data", onData);
});
...
This eliminates the need for the global in the first place. This should also allow multiple sockets and prevent the original error. I think. I'm new here, so I guess we will see.
EDIT
Alright. I've been interacting with your code via telnet. I've also read up on some of the documentation. First, the socket.on("connect", onConnect); listener should be moved(along with the onConnect function) into the global scope and changed to server.on("connection", onConnect);. The reason for this is that the socket event listener connect is a client side listener. We are working server side. The server side listener for new connections is connection and the server should be listening for it in the same way it is listening for connections on a particular port.
This part of your code should look like this now:
//more code up above here
....
function onData(d) {
var command = "";
for (i=0; i <= d.length - 1; i++) {
command += String.fromCharCode(d[i]);
if (d[i] == PACKET_SEPARATOR || i == d.length - 1 && !connection_ack) {
dataHandler(command);
command = "";
}
}
}
socket.on("data", onData);
});
function onConnect() {
console.log("Connected to Flash");
}
server.on("connection", onConnect);
....
//more code below here
However, the code would not recognize exit as a command via telnet. I was unable to figure this bit out. Since your question did not cover this problem it might just be me or you have it figured out.
EDIT 2
The code below keeps it local.
var server = net.createServer(function(socket) {
function onConnect() {
console.log("Connected to Flash");
socket.write("we're connected");
}
....
function onData(d) {
var command = "";
for (i=0; i <= d.length - 1; i++) {
command += String.fromCharCode(d[i]);
if (d[i] == PACKET_SEPARATOR || i == d.length - 1 && !connection_ack) {
dataHandler(command);
command = "";
}
}
}
onConnect();
socket.on("data", onData);
});

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

Resources