Ember.run.later will never execute under some conditions


#1

This is a cross post from a github issue: https://github.com/ebryn/backburner.js/issues/86

We are seeing this behavior intermittently:

  • Ember.run.later is called to schedule a future execution

  • Internally, this updates laterTimerExpiresAt to the next future execution timestamp and a browser setTimeout schedules the call and timer id is recored in laterTimer.

  • The computer goes to sleep

  • Computer wakes.

  • Intermittent but causes the bug: the timer never fires.

  • Now, laterTimerExpiresAt and laterTimer hold values that cause this updateLaterTimer to never execute its body, causing future schedule calls to never execute.

function updateLaterTimer(self, executeAt, wait) {
  if (!laterTimer || executeAt < laterTimerExpiresAt) {
    // we don't enter this block because 
    // executeAt > laterTimerExpiresAt and laterTimer has a value.
    ...

    // executeAt could also be in the past after a sleep/wake
    laterTimerExpiresAt = executeAt;
  }
}

Possible fix:

function updateLaterTimer(self, executeAt, wait) {
  var now = (+new Date());
  if (!laterTimer 
      || (executeAt < laterTimerExpiresAt) 
      || (laterTimerExpiresAt < now)) { // also check for stale timers

    if (laterTimer) {
      // immediately trigger any stale timers.
      if (laterTimerExpiresAt < now) {
        wait = 0;
      }
      clearTimeout(laterTimer);
    }   

    laterTimer = global.setTimeout(function() {
      laterTimer = null;
      laterTimerExpiresAt = null;
      executeTimers(self);
    }, wait);

    // base laterTimerExpiresAt on now and wait value
    // instead of possibly out of date executeAt
    laterTimerExpiresAt = now + wait;
  }   
}