1

I have a schedule option in my API what I did with Expressjs and NodeJS. Our backend calls this API with two parameters (userID & timestamp). The goal is to delete user informations (folders, documents, etc) at the specified time (..or few minutes later). The timestamp can be 5 minutes to 2 days from now.

When it happened the job is done and the API is waiting for an other call. The API can receive 1000 calls per day, so the performance is very important. What's the best way to run the function in the future?

async function scheduledAction(userId, timestamp) {
    var actionInFuture = await checkDate(timestamp);
    
    if(actionInFuture) {
        console.log('Action triggered');
    }
}

async function checkDate(timestamp) {
    await new Promise(resolve => {
        setTimeout(resolve, 1000)
    });
    
    // timestamp = 1627311533000
    if(Date.now() >= timestamp) {
        return true;
    } else {
        return checkDate(timestamp);
    }
}

app.get('/action', (req, res) => {
    scheduledAction(req.query.userId, req.query.timestamp);
} 
scheduledAction(req.query.userId, req.query.timestamp);
user3630024
  • 111
  • 1
  • 8
  • have you heard of setTimeout? that will prevent your code from the tight recursion that will eventually cause a stack overflow - unless v8 has proper tail recursion that is - have you noticed this problem in your code? – Bravo Jul 26 '21 at 13:33
  • You don't have any type of delay, so you will be constantly processing your code. Then once you hit the targeted time, your code will run and then it won't run again until the server restarts. Is these your intentions? – daddygames Jul 26 '21 at 13:34
  • 1
    oh, and Date.now is in milliseconds, so your trigger is set for January 19, 1970 :p which is why you probably haven't got the too much recursion problem (not a stack overflow as I previously stated) – Bravo Jul 26 '21 at 13:34
  • Trying to write a scheduler in JS like this isn't going to work well. Js is single threaded so once you block the thread nothing else is going to run. SetTimeout will probably work but it's execution time is not guaranteed. – Liam Jul 26 '21 at 13:36
  • @Liam - when you're dealing with hours or days, you wouldn't set the timeout for the full amount - you'd perhaps setTimeout's half way to the target on each step :p – Bravo Jul 26 '21 at 13:38
  • 1
    You'll need to preserve state somehow. If you restart the server you'd lose the timers. – MinusFour Jul 26 '21 at 13:40
  • @Bravo yes, I heared about setTimeout but I was not sure that's the best way. I thought it can cause memory issues. I didn't test the code, just shared my idea. The trigger is in ms too (1627309531 = Monday, 26 July 2021 16:25:31 GMT+02:00 DST) so probably that part works in the code. So you think for performance better to go with setTimeout? daddygames It's an API, users can call it again. – user3630024 Jul 26 '21 at 14:24
  • well most of solutions (all seem to be gone now except one) actually use setTimeout - it's the most sane solution – Bravo Jul 26 '21 at 22:14

1 Answers1

1

You can use Node Schedule package, https://www.npmjs.com/package/node-schedule

For example:

var schedule = require('node-schedule');
const date = new Date(1627309531*1000);

var j = schedule.scheduleJob(date, function(){
        console.log('Action triggered');
});
zvi
  • 3,677
  • 2
  • 30
  • 48
  • 1
    this basically uses setTimout's in a controlled way - perhaps overkill for a one-shot :p but why re-invent the wheel! – Bravo Jul 26 '21 at 13:42