bunkat / later

A javascript library for defining recurring schedules and calculating future (or past) occurrences for them. Includes support for using English phrases and Cron schedules. Works in Node and in the browser.
http://bunkat.github.io/later/
MIT License
2.42k stars 244 forks source link

Scheduled code firing twice (only for one timer) #207

Open zeg-io opened 7 years ago

zeg-io commented 7 years ago

I have a really weird situation.

I have four timers (setIntervals()) which are running. Two only fire once per day. One fires once per hour on the hour, and the other once per hour on the half hour.

Below is the output from my logs. The first thing that happens inside the setInterval function is it outputs the Update Device Fired line.

Notice that for some unknown reason it is firing one second before the target time, and then again at the actual time!

However, the other hourly event does not trigger twice although it does do the weird second before thing...and it is defined in the same way!

╭────────┤ Update Device Fired ├───────
│ 15:59:59 Determining last good insert
╭────────┤ Update Device Fired ├───────
│ 16:00:00 Determining last good insert
│ 16:00:00    ...Apr 4th, 2017 @ 15:30
│ 16:00:00    ...Apr 4th, 2017 @ 15:30
│ 16:00:00 Beginning pre-insert checks...
│ 16:00:00 Beginning pre-insert checks...
│ 16:00:01 Identified 3 clients
│ 16:00:01 Checking updates for devices since Apr 4th, 2017 @ 15:30
│ 16:00:01 Identified 3 clients
│ 16:00:01 Checking updates for devices since Apr 4th, 2017 @ 15:30
│ 16:00:08 Successful.
╰────────┤ Completed in: 8 seconds ├───────
 * Next device update: Thu Apr 20th 4:00 PM
│ 16:00:08 Successful.
╰────────┤ Completed in: 8 seconds ├───────
 * Next device update: Thu Apr 20th 4:00 PM
// <a bunch of includes above>

// on weekdays every hour between 8am and 5pm
let deviceUpdateSchedule = later.parse.recur()
                           .every(1).hour().between(8, 17)
                           .onWeekday()

// on weekdays every hour between 8am and 5pm
let hrUpdateSchedule = later.parse.recur()
                      .every(1).hour().between(8, 17)
                      .on(30).minute()
                      .onWeekday()
// --- snip---

updateDevicesTimer = later.setInterval(() => {
    let startTime = new Date()

    l('Update Device Fired').start().pending()
    updateDeviceHandler()
    .catch(err => console.error(err))
    .then(results => {
      l('Update completed.').end(startTime).success()
      if (results)
        log.pending(` * Next device update: ${moment(later.schedule(deviceUpdateSchedule).next(1)).format('ddd MMM Do h:mm A')}`)
    })
    .catch(err => {
      l('Update Error').div().error()
      console.error(err)
      l('Update completed.').end(startTime).error()
    })
  }, deviceUpdateSchedule)
MaxMem commented 7 years ago

This is probably a duplicate of my issue from a couple years ago:

https://github.com/bunkat/later/issues/90

There is a built-in buffer of one second because the timer often fires early, but over longer periods of time it can fire more than one second early, causing the duplication.

What I have done in my local copy is increase the buffer to 5 seconds, which has worked well.

In setTimeout, change:

if (diff < 1e3) {

To:

if (diff < 5e3) {