How make a node.js script to be restarted every hour? - node.js

I have a node.js script that creates a websocket connection to a crypto trading site (bitmex). It streams price data.
For some reason after an hour or two the stream goes bad and the prices (if streamed at all) are inacurate.
For now I restart it manually every hour but I need that to be done automatically. How can I do that?
Here is the code of the script:
var WebSocket = require('ws');
var ws = new WebSocket("wss://www.bitmex.com/realtime");
var couchbase = require('couchbase')
var cluster = new couchbase.Cluster('couchbase://localhost/');
cluster.authenticate('xxxxxx', 'xxxxxxx');
var bucket = cluster.openBucket('test');
var N1qlQuery = couchbase.N1qlQuery;
let num_msg = 0;
ws.onopen = function(){
ws.send(JSON.stringify({"op": "subscribe", "args": [
"trade:XBTUSD",
"trade:LTCZ18"]
}))
};
ws.onmessage = function(msg){
var response = JSON.parse(msg.data);
num_msg++
if(num_msg > 50) {
var coin = response['data'][0]['symbol'];
var price = response['data'][0]['price'];
//console.log(coin + ":" + price + "\n");
bucket.manager().createPrimaryIndex(
function(){
bucket.upsert( coin,
{
'price': price
},
function (err, result){
});
});
}
};
EDIT: I missed to mention that currently I use Windows 7 system (eventhough I do need to move to Ubuntu or similar).
EDIT 2: Final version of my code :)
const cron = require("node-cron");
var WebSocket = require('ws');
var couchbase = require('couchbase');
var dateTime = require('node-datetime');
let now = new Date();
minutes = now.getMinutes() + 1;
if(minutes + 30 > 59) {
minutes1 = minutes - 30;
} else {
minutes1 = minutes - 30;
}
if(minutes > minutes1) {
s_cron = minutes1 + "," + minutes + " * * * *";
} else {
s_cron = minutes + "," + minutes1 + " * * * *";
}
cron.schedule(s_cron, () => {
console.log("---------------------");
console.log("Running Cron Job");
var dt = dateTime.create();
var formatted = dt.format('Y-m-d H:M:S');
console.log(formatted);
// create bitmex ws
var ws = new WebSocket("wss://www.bitmex.com/realtime");
// connect to couchbase
var cluster = new couchbase.Cluster('couchbase://localhost/');
cluster.authenticate('xxxxxxxx', 'xxxxxxxxxx');
var bucket = cluster.openBucket('test');
var N1qlQuery = couchbase.N1qlQuery;
let num_msg = 0;
ws.onopen = function(){
ws.send(JSON.stringify({"op": "subscribe", "args": [
"trade:XBTUSD",
"trade:LTCZ18"]
}))
};
ws.onmessage = function(msg){
var response = JSON.parse(msg.data);
num_msg++
if(num_msg > 50) {
var coin = response['data'][0]['symbol'];
var price = response['data'][0]['price'];
//console.log(coin + ":" + price + "\n");
bucket.manager().createPrimaryIndex(
function(){
bucket.upsert( coin,
{
'price': price
},
function (err, result){
//bucket.disconnect()
});
});
}
};
});

Try 'node-cron': more at https://www.npmjs.com/package/node-cron Hope that works.

Consider using cron to restart every hour. Your crontab entry would look like:
0 * * * * <command to restart your app>
If you can't or don't want to use your system crontab or equivalent (not sure what it would be on Windows), you can use pm2.
pm2: https://www.npmjs.com/package/pm2
For how to make pm2 restart every hour, see https://github.com/Unitech/pm2/issues/1076 or https://stackoverflow.com/a/38062307/436641.
Another option would be node-cron: https://www.npmjs.com/package/node-cron

Related

Socket.io fs.readFileSync for many connections at same time

This is not really a question, but I wonder to know if what I did is correct because its working!
So, lets to the question, I`m monitoring many interfaces (PPPoE clients) at same to know its traffic reading the statistics from linux.
I`m using npm packages: express, socket.io and socket.io-stream.
Client:
var sessionsAccel = $('table.accel').DataTable([]);
sessionsAccel.on('preDraw', function() {
$('.interfaceAccel').each(function(i) {
var t = $(this).data();
sockets['socket' + t.id].disconnect();
delete speeds['tx_bytes' + t.id];
delete speeds['rx_bytes' + t.id];
});
})
.on('draw', function() {
$('.interfaceAccel').each(function(i) {
var t = $(this).data();
sockets['socket' + t.id] = io.connect('http://172.16.101.2:3000/status', {
query: 'interface=' + t.interface,
'forceNew': true
});
sockets['socket' + t.id].on("connect", function() {
ss(sockets['socket' + t.id]).on('sendStatus', function(stream, data) {
if (typeof speeds['tx_bytes' + t.id] != 'undefined') {
var speedtx = (data.tx_bytes - speeds['tx_bytes' + t.id]) * 8 / 1000;
var speedrx = (data.rx_bytes - speeds['rx_bytes' + t.id]) * 8 / 1000;
if (speedtx > 1000) {
speedtx = speedtx / 1000;
speedtx = speedtx.toFixed(2);
speedtx_info = speedtx + ' Mbps';
} else {
speedtx = speedtx.toFixed(2);
speedtx_info = speedtx + ' kbps';
}
if (speedrx > 1000) {
speedrx = speedrx / 1000;
speedrx = speedrx.toFixed(2);
speedrx_info = speedrx + ' Mbps';
} else {
speedrx = speedrx.toFixed(2);
speedrx_info = speedrx + ' kbps';
}
$('.tx_' + t.id).html(speedtx_info);
$('.rx_' + t.id).html(speedrx_info);
}
speeds['tx_bytes' + t.id] = data.tx_bytes;
speeds['rx_bytes' + t.id] = data.rx_bytes;
});
});
});
})
Server:
const app = require('express')();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
const ss = require('socket.io-stream');
const path = require('path');
const fs = require('fs');
function getIntInfo(interface) {
if(fs.existsSync('/sys/class/net/'+ interface +'/statistics/tx_bytes')) {
var tx_bytes = fs.readFileSync('/sys/class/net/'+ interface +'/statistics/tx_bytes').toString();
var rx_bytes = fs.readFileSync('/sys/class/net/'+ interface +'/statistics/rx_bytes').toString();
var tx_packets = fs.readFileSync('/sys/class/net/'+ interface +'/statistics/tx_packets').toString();
var rx_packets = fs.readFileSync('/sys/class/net/'+ interface +'/statistics/rx_packets').toString();
return {tx_bytes : tx_bytes, rx_bytes : rx_bytes, tx_packets: tx_packets, rx_packets: rx_packets};
}else
return false;
}
io.of('/status').on('connection', function(socket) {
var query = socket.handshake.query['interface'];
var timer = setInterval(function() {
var stream = ss.createStream();
var info = getIntInfo(query);
ss(socket).emit('sendStatus', stream, info);
}, 1000);
socket.on('disconnect', function(){
socket.disconnect(true);
//console.info('disconnected user (id=' + socket.id + ').');
});
})
http.listen(3000, function(){
console.log('listening on *:3000');
});
That's it, every row from Datatable (which is the interface) open a socket connection and retrieve the statistics.
My question is, this will mess up my server with many I/O reading these files?
Since you're doing this every second for every connected client, it seems like you should probably cache this data so it doesn't have to be read from the disk or sent over the wire when it hasn't changed to save both server load and bandwidth usage. But, the details of how to best do that depend upon knowledge about your particular application that you haven't included.
You can at least use asynchronous I/O like this:
const util = require('util');
const fs = require('fs');
const readFile = util.promisify(fs.readFile);
function getIntInfo(interface) {
function readInfo(name) {
return readFile('/sys/class/net/'+ interface +'/statistics/' + name).then(data => data.toString());
}
return Promise.all(
readFile('tx_bytes'),
readFile('rx_bytes'),
readFile('tx_packets'),
readFile('rx_packets')
).then(([tx_bytes, rx_bytes, tx_packets, rx_packets]) => {
return {tx_bytes, rx_bytes, tx_packets, rx_packets};
}).catch(err => {
console.log(err);
return false;
});
}
And, you have to stop the interval any time a client disconnects and change how it calls getIntInfo():
io.of('/status').on('connection', function(socket) {
var query = socket.handshake.query['interface'];
var timer = setInterval(function() {
getIntInfo(query).then(info => {
var stream = ss.createStream();
ss(socket).emit('sendStatus', stream, info);
});
}, 1000);
socket.on('disconnect', function(){
// stop the timer for this connection
clearInterval(timer);
});
});
Now that I think about it a bit more, you could improve scalability quite a bit by having just one interval timer that was reading the data and then sending that one set of data to all listening clients that had connected to the /status namespace. You would reduce the file reading from once per second for every client to just once per second for no matter how many clients.

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

how to find free time slot of a day if busy slots are given in nodejs

For example clinic working hours on specific date are as follow:
var workingStartTime = 2018-05-12T08:00:00.000Z;
var workingEndTime = 2018-05-12T22:00:00.000Z;
Doctor's already scheduled appointments on the same date are as follow:
var busySlots =
[ {
start_time: '2018-05-12T14:30:00.000Z',end_time:'2018-05-12T17:45:00.000Z'
},
{
start_time: '2018-05-12T20:30:00.000Z',end_time: '2018-05-12T21:45:00.000Z'
}]
I need to fetch available time slots of doctor which are greater than 60 minutes starting from 2018-05-12T08:00:00.000Z to 2018-05-12T22:00:00.000Z
timings of a day with minimum line of code in nodejs.
Following problem is similar to my query:
How to find free time slot based on available time slot and booked time slot?
But above code is in php and i need code written in nodejs.
Below code might be not optimized but it works for me:
function (cb){
var duration = 60;
var freeSlots = [];
var workingStartTime = 2018-05-12T08:00:00.000Z;
var workingEndTime = 2018-05-12T22:00:00.000Z;
var busySlots = [];
busySlots.push({ start_time: "2018-05-12T14:30:00.000Z",end_time: "2018-05-12T17:45:00.000Z" }) ;
busySlots.push({ start_time: "2018-05-12T20:30:00.000Z",end_time: "2018-05-12T21:45:00.000Z" }) ;
var beginAt = workingStartTime;
var overAt = workingEndTime;
var count = 0;
var last = busySlots.length;
async.forEach(busySlots, function (item, callback){
/*** Library funcition to gind difference between two dates (Minutes) ***/
var diff = libFunc.getRange(beginAt, item.start_time,TIME_UNITS.MINUTES);
if(diff > duration){
let free = {"start_time":beginAt , "end_time":item.start_time};
freeSlots.push(free);
beginAt = item.end_time;
count += 1;
/** Process for end slot **/
if(last == count){
var diff = libFunc.getRange(item.end_time, overAt, TIME_UNITS.MINUTES);
if(diff > duration){
let free = {"start_time":item.end_time , "end_time":overAt};
freeSlots.push(free);
callback();
}else{
callback();
}
}else{
callback();
}
/** Process for end slot **/
}else{
beginAt = item.end_time;
count += 1;
/** Process for end slot **/
if(last == count){
var diff = libFunc.getRange(item.end_time, overAt, TIME_UNITS.MINUTES);
if(diff > duration){
let free = {"start_time":item.end_time , "end_time":overAt};
freeSlots.push(free);
callback();
}else{
callback();
}
}else{
callback();
}
/** Process for end slot **/
}
}, function(err) {
// console.log(freeSlots);
cb(null);
});
},

NodeJS Script Runs on Local Machine but Not in Firebase Cloud Functions?

My script written in NodeJS connects to Firebase, checks my Firebase Database and even successfully sends notifications when results from my database return true... However, it only works when I run it from my local machine. I deploy it to Firebase and it will not work. Could someone please advise? Thank you.
I hate asking on here because I'm a newbie but I have spent hours tonight trying to find an answer...
INDEX.JS
// Firebase Functions
const functions = require('firebase-functions');
var admin = require("firebase-admin");
// Default admin firebase configuration
admin.initializeApp(functions.config().firebase);
// var serviceAccount = require("xxxxxx-80xxxxd-firebase-adminsdk- xxxxxxx.json");
var moment = require('moment');
var FCM = require('fcm-push');
var dateTime = require('node-datetime');
var serverKey = 'xxxxxxxxxxxxxpSELZBjQYwpZgmxxxxxxxxxxx';
var fcm = new FCM(serverKey);
//Initial function call:
exports.CheckDates = functions.https.onRequest((req, response) => {
// Get a database reference to our posts
var db = admin.database();
var ref = db.ref("records");
var userToken = '';
var itemExpires = '';
var itemName = '';
var reminded = '';
var itemCount = 0;
var counter = 1;
var itemFoundCount = 0;
var dt = dateTime.create();
var formatted = dt.format('m-d-Y');
ref.once("value", function (recordsSnapshot) {
recordsSnapshot.forEach(function (recordsSnapshot) {
var mainKey = recordsSnapshot.key;
recordsSnapshot.forEach(function (child) {
var key = child.key;
var value = child.val();
if (key == 'Account') {
userToken = value.userToken;
}
if (key == 'Items') {
recordsSnapshot.child("Items").forEach(function (itemsSnapshot) {
counter++;
if (itemFoundCount === 0) {
itemFoundCount = itemsSnapshot.numChildren();
}
var itemsChildkey = itemsSnapshot.key;
var itemsChildvalue = itemsSnapshot.val();
itemExpires = itemsChildvalue.itemExpires;
itemName = itemsChildvalue.itemName;
reminded = itemsChildvalue.reminded;
moment().format('YYYY-MM-DD');
var currentDate = moment();
var otherTime = moment(reminded);
if (typeof reminded !== 'undefined') {
if (currentDate.diff(otherTime, 'days') >= 30) {
if (currentDate.diff(itemExpires, 'days') <= 90) {
itemCount++;
console.log("Expire date is less than " +
currentDate + " by 90 days = " + (currentDate.diff(otherTime, 'days') <=
90));
db.ref("records/" + mainKey + "/Items/" +
itemsChildkey + '/reminded').set(formatted);
}
}
} else {
itemCount++;
db.ref("records/" + mainKey + "/Items/" + itemsChildkey +
`enter code here`'/reminded').set(formatted);
}
if (counter == itemFoundCount && itemCount > 0) {
console.log(itemFoundCount);
var message = {
to: userToken, // required fill with device token or
topics
notification: {
title: 'Item Expire Notification',
body: itemCount + ' is about to expire.'
}
};
//callback style
fcm.send(message, function (err, response) {
if (err) {
console.log("Something has gone wrong!");
} else {
console.log("Successfully sent with response: ",
response);
}
});
itemCount = 0;
itemFoundCount = 0;
counter = 1;
}
});
}
});
});
});
response.send(200, "ok");
}) // END exports.CheckDates
Obviously, I remove the Exports.CheckDates lines when I run it locally but it wasn't showing up at all without the exports on Firebase's console. It returns warnings locally and on Firebase console but it works on one and not the other.
Please disregard this question. The script adds the date that the last time a notification was sent to the item's "Reminded" key in the database... this prevents notifications from going out every day for the same thing..
It ran on my local machine, and did it's job but I couldn't figure out why it wouldn't run again... well, ha! At least we know that part works.

setTimeout() function is not executed properly

I have to send an SMS 15 minutes before the appointment is there. I have written the code, but it is called at the time of execution itself. Is there any other method or how do I solve this?
"RP.remindePatient" is the function that has to be called 15 minutes before the appointment time.
sendApptConf(s) {
var number = Phone;
var msg = urlencode("Hello " );
var smsData = 'username=' + username + '&hash=' + hash + '&sender=' + sender + '&numbers=' + number + '&message=' + msg;
var options = {
host: 'api.textlocal.in',
path: '/send?' + smsData
};
var callback;
console.log(options);
callback = function (response) {
var str = '';
// Another chunk of data has been recieved, so append it to `str`
response.on('data', function (chunk) {
console.log("new Data received")
str += chunk;
console.log(str);
});
// The whole response has been received, so we just print it out here.
response.on('end', function () {
console.log(str);
});
}
http.request(options, callback).end();
// Send SMS using Textlocal DONE
const convertTime = consultDate + ' ' + consultTime;
var d = new Date(convertTime);
var ms = d.getTime();
var milliLess15 = ms - (15 * 60 * 1000);
console.log(milliLess15);
setTimeout(function () {
console.log("I should be called after some delay")
RP.remindePatient(userPhone, patientName, drName, consultMode, consultDate, consultTime, transId, email, paymentDetails);
}, milliLess15);
I think there is a small issue in your logic. As you would already know, setTimeout(function () {}, milliseconds) will fork the function() after milliseconds you have specified.
Now let's focus on the below snippet of code:
const convertTime = consultDate + ' ' + consultTime;
var d = new Date(convertTime);
var ms = d.getTime();
var milliLess15 = ms - (15 * 60 * 1000);
Let's say your appointment is at 12:00 pm today (in millisec let's say 1492776423) and current execution time is 10:00 am (in millisec 1485576423). By your logic, you are calling the function() after: var milliLess15 = ms - (15 * 60 * 1000) which is 1492776423 - (15 * 60 * 1000) = 1491876423. Note here that, you don't want to call function() after 1491876423 millisec. Rather you want to call it after millisec equivalent of 12:00 - 10:00 - 00:15. So your logic should look something like:
const convertTime = consultDate + ' ' + consultTime;
var d = new Date(convertTime);
var ms = d.getTime();
var currentTime = new Date();
var currentTimeMilli = currentTime.getTime();
var milliLess15 = ms - (15 * 60 * 1000) - currentTimeMilli;
Rest of the code will remain the same. Hope this answer helps you!
Don't call the variable after timeout. Just put in:
setTimeout(function () {
console.log("I should be called after some delay")
RP.remindePatient(userPhone, patientName, drName, consultMode, consultDate, consultTime, transId, email, paymentDetails);
}, 900000);

Resources