node-cron looping endlessly on vm - node.js

Im having a cron job set up on a gcloud compute instance.
It runs as expected on my local, but on the gcloud instance it waits until the first run and then starts to execute in an endless loop without a time gap.
async function runScript() {
...
}
cron.schedule("* */30 * * * *", () => {
runScript();
});

So I still dont know what the issue was, but I figured out a solution.
The cron-job needs to be setup in the following way:
cron.schedule("0 */30 * * * *", () => {
Now it also runs fine on the vm

Related

Node: Storing function names in a variable and then calling them

I am writing a node application that uses node-cron to schedule certain function to run at specific times. Currently the code for this is embedded in the main application. I want to move the configuration of scheduled tasks out to a config file, so want need to store the function names in a variable to achieve this, as the schedule tasks call out a number of functions in different modules etc.
For information the syntax to schedule a cron task is this:
cron.schedule('* * * * *', () => {functiontocall()});
The code block below shows how I am currently storing the tasks in an object and trying to schedule them with node-cron.
mycronobj = [
{scheduletime : "* * * * *", schedulefunction : 'testfunction1'},
{scheduletime : "*/5 * * * *", schedulefunction : 'testfunction2'},
{scheduletime : "*/10 * * * *", schedulefunction : 'testfunction3'},
]
for (item in mycronobj) {
cron.schedule(mycronobj[item].scheduletime, () => {mycronobj[item].schedulefunction()});
}
However this doesn't work, the scheduled functions don't run. I have tried storing the functions names as a string (as shown) or direct as
{scheduletime : "* * * * *", schedulefunction : testfunction1()}
When trying to add the scheduled function I have tried this with the following syntaxes:
mycronobj[item].schedulefunction()
mycronobj[item]schedulefunction
mycronobj[item].schedulefunction
None of which have worked for me. I have tried looking for an answer to this and I tried using eval(), but this also didn't work correctly, the outcome was that a task with first schedule ("* * * * *") was scheduled with the last function 'testfunction3' was applied, also I dont really want to use eval as I have read its not great practice and can be avoided if you know what your doing (clearly I don't).
Other options I have come across is to use Window which doesn't exist in Node or This, which I cannot get to work either.
Thanks in advance.
The reason your code isn't working is that mycronobj[item]schedulefunction is a string so is not invokable. You need to turn this string into a reference to the function with the same name.
The simplest solution to this is using eval, e.g:
for (item of mycronobj) {
cron.schedule(item.scheduletime, () =>
eval(`${item.schedulefunction}()`);
}
However this is a really bad idea, and allows for arbitrary code execution which is generally considered a very bad thing (tm).
Node gives you a slightly safer alternative to this using the vm module, which can create a limited sandbox in which your code can execute:
const vm = require("vm");
let context = vm.createContext({ foo });
for (item of mycronobj) {
cron.schedule(item.scheduletime, () =>
vm.runInContext(`${item.schedulefunction}()`, context);
}
This is only marginally better though since it can still allow arbitrary code execution, so by far the safest option is just to explicitly list exactly which functions are allowed to be called:
const commands = {
testfunction1: () => console.log("I am 1"),
testfunction2: () => console.log("I am 2"),
testfunction3 // Reference existing function
}
function testfunction3() { console.log("I am 3"); }
for (item of mycronobj) {
let func = commands[item.schedulefunction];
if (!func) { throw new Error(`Unknown command: "${item.schedulefunction}"`); }
cron.schedule(item.scheduletime, func);
}
This also has the benefit of determining during setup whether functions are valid rather than only when the cron job runs.

Node.js: Get time till next cron job

I have a server that has a cron job running at certain times in the day. I want to get the time till the next job will execute. I looked at the cron and node-cron packages in npm, but they don't seem to have this functionality.
How can I implement this functionality by myself for these packages?
The cron package allows you to get the next runs of the cron job, so you can use this to determine the time until the next run.
This is exposed in the CronJob.nextDates() function.
const CronJob = require("cron").CronJob;
const cronJob = new CronJob(
"*/30 * * * * *",
() => {
console.log("Timestamp: ", new Date());
},
null,
true,
"UTC"
);
setInterval(() => {
let timeUntilNextRunSeconds = cronJob.nextDates(1)[0].unix() - new Date().getTime()/1000;
console.log("Time until next run (s): ", Math.round(timeUntilNextRunSeconds));
}, 1000);

How to use Generic cron jobs in node application?

I have node application in which I want to run tasks on daily basis. So I want to use node-cron to schedule tasks but not like this:
var cron = require('node-cron');
cron.schedule('* * * * *', function(){
console.log('running a task every minute');
});
I need some generic solution so that at one place I have just empty body for cron job that takes different functions from a different location. That means in total we have two files, one which has just cron job function handler and other have a list of cron jobs. From where we want to run these jobs we just need require and some basic calling.
Can anyone suggest me this solution?
I got my solution. Using node-cron-job module I have achieved what I wanted. Let me explain in detail:-
First i created new file which contains jobs, lets name it jobs.js :-
// jobs.js
exports.first_job = {
on:"* * * * * " //runs every minute
},
job: function () {
console.log("first_job");
},
spawn: true
}
exports.second_job = {
on: "*/2 * * * * *", //runs every 2 second
job: function () {
console.log("second_job");
},
spawn: false // If false, the job will not run in a separate process.
}
Here, we define two jobs name first_job and second_job. We can define as many required.
Finally, we need to call these jobs from any location by these simple steps:-
// main.js
var cronjob = require('node-cron-job');
cronjob.setJobsPath(__dirname + '/jobs.js'); // Absolute path to the jobs module.
cronjob.startJob('first_job');
cronjob.startJob('second_job');
We can call all jobs in a single call like this:-
cronjob.startAllJobs();

How to schedule process in the way that it should run immediately for the first time and run with scheduled time from second time in node js

I tried with node-schedule package
[https://www.npmjs.com/package/node-schedule][1]
var schedule = require('node-schedule');
var j = schedule.scheduleJob('42 * * * *', function(){
console.log('The answer to life, the universe, and everything!');
});
But if I schedule for 10 minutes and start the process it is processing after 10 minutes.
In my case, I need the process to be run for the first time and later it should run with scheduled time.
Is there any solution for this kind of issue?
Thanks in Advance..
There is a way to do it , just found it
let startTime = new Date(Date.now()) ;
var j = schedule.scheduleJob({ start: startTime, rule:'42 * * * *'},
function(){
console.log('The answer to life, the universe, and everything!');
});
Hope this helps
See this documentation of node-schedule
You can use codes from https://github.com/kelektiv/node-cron.
Then you can fire the crontab job at the second when you start nodejs program. After the crontab job will be run at certain interval.
This is an example to run the job immediately when creating the crontab work.
const CronJob = require('cron').CronJob;
const job = new CronJob({
cronTime: '0 */5 * * * *',
onTick: () => console.log(`Round at ${new Date()}`);
runOnInit: true
});
job.start();
In codes above, the "console.log" will be run when I start my program. Then it will run at every 5 minutes. For more usage, you can refer to the lib provided.

cron job in node js running multiple times

I am running a cron job using the module node-cron for node js . My code is below.
var Job = new CronJob({
cronTime: '* * 01 * * *', //Execute at 1 am every day
onTick : function() {
co(function*() {
yield insertToDatabase(); //this is the function that does insert operation
}).catch(ex => {
console.log('error')
});
},
start : false,
timeZone: 'Asia/Kolkata'
});
I need to execute this only one time but this cronjob once starts runs multiple times due to which same data gets inserted to my database. I only need to run this job only one time. What should i do.
I know I am late to the party but I think that I have a solution. I hope this can help someone else in the future (Hi future!)
I encountered what I think to be the same issue as the asker, that is, the OnTick function executes multiple times after the scheduled time, this appeared to the author to be an endless loop. The asker expected this function to run only once at the scheduled time everyday (today, tomorrow, etc).
With that in mind the cause of this "issue" is simple. The cron job is scheduled to to exactly this. The cron time entered is * * 01 * * * which means the hour is 01 (aka 1:00am) but the minutes and seconds are *. This means any minute and any second where the hour is 01. So this will run from 1:00am up until 1:59am. It will run for each second of each minute until 2:00am. If the author had waited until 2:00am the "looping" would have ceased.
The solution is to set the seconds and minutes to anything that is not * (0 in my case worked).
I feel really silly for not having figured this out right away but here it is!
You can call Job.stop() from onTick:
onTick : function() {
Job.stop();
co(function*() {
yield insertToDatabase();
}).catch(ex => {
console.log('error');
});
}
In my case, i changed my code from this :
var job = new CronJob('*/59 * * * *', onTick, onComplete, true, 'Asia/Kolkata'); // onTick and onComplete is a function, which i'm not showing here
job.start();
To this :
var job = new CronJob('*/59 * * * *', onTick, onComplete, false, 'Asia/Kolkata'); // onTick and onComplete is a function, which i'm not showing here
job.start();
Thanks

Resources