Sanity check: using setTimeout and setInterval together


#1

Hi there.

I need to run a function at the beginning of each day (to add extra vacation time to an employee’s balance) and I wanted to share what I’ve come up with.

Here’s how I plan everything to work:

  1. Get the diff between now and the next interval
  2. setTimeout() to wait until the next interval
  3. Run daily code once when setTimeout() expires (or the first run will be missed)
  4. setInterval() to wait 24 hours
  5. Clear setTimeout()
  6. Let setInterval() run indefinitely

(Discourse wants a paragraph here or else it won’t render the code properly.)

Meteor.startup(function () {
  // get current Moment(), round up to the next day at 12AM, get diff between
  // now and that time
  var waitTillMorning = moment().startOf('day').add(1, 'd').diff(moment());
  var millisPerDay = 86400000;

  var timeout = Meteor.setTimeout(function () {
    console.log('timeout started');

    Meteor.setInterval(function () {
      console.log('interval executed');
    }, millisPerDay);
    
    Meteor.clearTimeout(timeout);
  }, waitTillMorning);
});

Is this the right way to go about this? A few things I’m not sure of:

  1. Is Meteor.clearTimeout() necessary here?
  2. Is this method safe to run for an extended period of time? Or should I plan to restart the Meteor process on an interval (weekly?) at the server?

Thanks.


#2

When you are doing a setTimeout with plain JS function or with Meteor.setTimeout, the callback function passed is executed (approximaterly) at the end of the timeout.
So your first console.log(“timeout started”) should be “timeout finished”.
Then your setInterval start and never ends.
The clearTimeout is unecessary (and too late since at this time the timeout has already expired !).
Other parts of your code seems correct (i have not checked the moment line, since it tends to give me headaches…).


#3

So your first console.log(“timeout started”) should be “timeout finished”.

I really meant “code within timeout was just executed” but I can see why it didn’t appear that way.

Then your setInterval start and never ends.

Yes, that’s what I intended. Are you suggesting I should set some kind of end to setInterval and restart the Meteor process?


#4

No no, this is correct.


#5

While this all looks sane, it is not scalable. If you happen to run more than one instance of your app (say it grows) then everything will have run twice.

I’d strongly suggest you o for one of those persisted/synced timer/cron packages from atmosphere. I generally go for percolate:syncedcron and am quite happy with it.


#6

Agree, I use percolate:synced-cron and it works great. No need reengineer unless you have a unique situation.


#7

True true. I will check it out.