Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is setTimeout safe for scheduling jobs over large spans of time?

I'm writing an application in Node.js that needs to schedule functions to be run at specific times. Hours or sometimes days in the future. Currently, I'm doing so with something similar to this:

const now = Date.now();
const later = getSomeFutureTimestamp();
setTimeout(function() {
  // do something
}, later - now);

I'm wondering if setTimeout is the proper tool for this job or if there is a tool more suited for long intervals of time. One thing to note is I don't need great precision; if the job runs within a few minutes of the scheduled time, everything should still be fine.

like image 868
SimpleJ Avatar asked Oct 22 '15 16:10

SimpleJ


People also ask

Does setTimeout affect performance?

No significant effect at all, setTimeout runs in an event loop, it doesn't block or harm execution.

Does setTimeout run forever?

The setTimeout() is executed only once. If you need repeated executions, use setInterval() instead. Use the clearTimeout() method to prevent the function from starting.

What will happen if we call setTimeout () with a time of 0 ms?

1 Answer. To explain: If you call setTimeout() with a time of 0 ms, the function you specify is not invoked right away. Instead, it is placed on a queue to be invoked “as soon as possible” after any currently pending event handlers finish running.

Is setTimeout a blocking call?

Explanation: setTimeout() is non-blocking which means it will run when the statements outside of it have executed and then after one second it will execute. All other statements that are not part of setTimeout() are blocking which means no other statement will execute before the current statement finishes.


1 Answers

setTimeout should be fine. It's only really delayed if there's blocking code running at the moment when it's meant to execute. So setTimeout is typically 20 milliseconds late. But since your margin is minutes, I don't think it'll be an issue.

However, I'd suggest storing the timestamp at which things should trigger, and just periodically check. That way you only have 1 timer running at any given time.

You also get to keep your timestamps as absolute timestamps - not as relative, "milliseconds in the future" values. That also lets you store them between server restarts, which you can't do as easily with relative times. With your code, the only record of a job being queued is that there's a timer running. If that timer disappears for any reason, you lose all record of a job having been scheduled.

Something like:

function checkForScheduledJobs() {
  var now = Date.now(),
      job;

  // assuming here that the jobs array is sorted earliest to latest
  while(jobs.length && jobs[0].timestamp < now) {
    jobs.shift().callback();
  }

  setTimeout(checkForScheduledJobs, 60000); // check each minute
}

You just need to kick it off once. This could be done in an addScheduledJob function (which would also sort the jobs array after adding something to it, etc.)

like image 188
Flambino Avatar answered Oct 16 '22 21:10

Flambino