4

I have 2 node.js webservers. I cache data inside webservers. I sync the cache load/clear based on system time. I have done time sync of all my hosts.

Now I clear cache every 15 mins using following code:

millisTillNexthour = "Calculate millis remaining until next hour"

setTimeout(function() {
  setInterval(function() {
    cache.clear();
  }, 60000*15);
}, millisTillNexthour);

My expectation is even if this process runs for ever, cache will be cleared every 15th minute of each hour of the day.

My question is: can setInterval drift over time?

For eg: right now it clears cache at 10:00 10:15 10:30 10:45 11:00 ......

Can it happen that instead of 10:15 system time, setInterval gets executed at 10:20 system time when it was supposed to clear cache at 10:15??

I am not sure how this works. Please shed some light. I hope I explained my question well.

GJain
  • 5,025
  • 6
  • 48
  • 82
  • Unless something else is blocking the execution of it, it should be executed as close to `:15` as it can be, no sooner – Ian Aug 10 '13 at 22:50
  • 1
    Theoretically no. `setInterval` is designed specifically to get around the problem that would come from using a `setTimeout` which calls itself (and would drift). However Ian is right; if something blocks it for 5 minutes while it's supposed to be running the callback, it won't run until the block has lifted. Don't rely on this for financial transactions or nuclear deterrents. – Dave Aug 10 '13 at 22:56
  • I found another similar post: http://stackoverflow.com/questions/985670/will-setinterval-drift – GJain Aug 10 '13 at 23:25

6 Answers6

2

I'm probably more than a bit late to the party here, but this is how I solved this particular time-slipping problem just now, using a recursively called setTimeout() function instead of using setInterval().

var interval = 5000;
var adjustedInterval = interval;
var expectedCycleTime = 0;

function runAtInterval(){
    // get timestamp at very start of function call
    var now = Date.now();

    // log with time to show interval
    console.log(new Date().toISOString().replace(/T/, ' ').replace(/Z/, '') + " runAtInterval()");

    // set next expectedCycleTime and adjustedInterval
    if (expectedCycleTime == 0){
        expectedCycleTime = now + interval;
    }
    else {
        adjustedInterval = interval - (now - expectedCycleTime);
        expectedCycleTime += interval;
    }

    // function calls itself after delay of adjustedInterval
    setTimeout(function () {
        runAtInterval();
    }, adjustedInterval);
}

On each iteration, the function checks the actual execution time against the previously calculated expected time, and then deducts the difference from 'interval' to produce 'adjustedInterval'. This difference may be positive or negative, and the results show that actual execution times tend to oscillate around the 'true' value +/- ~5ms.

Either way, if you've got a task that is executing once a minute, and you run it for an entire day, using this function you can expect that - for the entire day - every single hour will have had 60 iterations happen. You won't have that occasional hour where you only got 59 results because eventually an entire minute had slipped.

HomerPlata
  • 1,687
  • 5
  • 22
  • 39
1

setInterval is definitely drifting (although I agree that it should not be). I'm running a Node.js server with an interval of 30 seconds. On each tick, a few async web requests are made which from beginning to end take roughly 1 second. No other user-level/application processing happens in the intervening 29 seconds.

However, I notice from my server logs that over the course of 30 minutes, a drift of 100ms occurs. Of course, the underlying operating system is not to blame for the drift and it can only be some defect of Node.js's design or implementation.

1

I am very disappointed to notice that there is a bug in the NodeJS implementation of setInterval. Please take a look at here:

https://github.com/nodejs/node/issues/7346#issuecomment-300432730

mitsos1os
  • 2,170
  • 1
  • 20
  • 34
0

You can use Date() object to set specific time and then add a certain number of milliseconds to the date.

Dimitri Vorontzov
  • 7,834
  • 12
  • 48
  • 76
  • this would provide no extra robustness over what they already have. – Dave Aug 10 '13 at 23:00
  • Unless it's in based on an object or array containing representation of every fifteen minutes time of the 24 hours, and cache is purged on the event. Just thinking aloud here, though. – Dimitri Vorontzov Aug 10 '13 at 23:09
  • ... based on the thought that something may indeed gunk up the system resources, but the computer clock will keep ticking away. – Dimitri Vorontzov Aug 10 '13 at 23:14
  • internally, `setInterval` uses the system clock. To be clear, `setInterval` will never drift, but it may have to wait before firing (if something is blocking it at the time when it is supposed to run). That applies to everything which you could possibly do, short of taking over the kernel duties and hot-waiting, although it's less of an issue in other languages where threading is more prevalent (there are fewer things which can cause it to block). – Dave Aug 10 '13 at 23:20
  • OK. You're right. In this case – what if that function is run on a web worker? Would that help? – Dimitri Vorontzov Aug 10 '13 at 23:22
  • it should bring it up-to-par with other languages, yes. But I believe WebWorkers limit what you're allowed to actually do, so it might not be practical. node.js might have built-in threading support for (e.g.) serving requests vs running background tasks; I'm not sure. – Dave Aug 10 '13 at 23:25
0

It definitly can because of how Javascript works (See Event Loop)

Javascript event loop executes the setInterval queue when other queued events are finished. These events will take some time and it will effect your setInterval function's execute time and it will eventually drift away as time passes.

-1

setInterval should not drift in a perfect world. It might be delayed due to other things taking up system resources. If you need a more precise solution to what you have, use the clock() function to " calibrate " your nodes.

user2503170
  • 145
  • 1
  • 8