Akka scheduler() is late on every repeat

2019-05-12 12:30发布

问题:

I have simple scheduler for repeating task every 1 second:

Cancellable task = Akka.system().scheduler().schedule(
        Duration.create(0, TimeUnit.MILLISECONDS),
        Duration.create(1, TimeUnit.SECONDS),
        actor, new TickMsg("Tick", 0, 120)
);

Unfortunately every pass is late for the ticker-duration so finally actor receives TickMsg exactly 100 ms later - ok, that's described in the doc and it's clear to me:

It does not execute tasks at the exact time, but on every tick, it will run everything that is overdue.

What I can't understand is why every pass is late, which de facto means that every pass instead 1000ms needs 1100ms. In result after 10 passes we have 1 second of delay, after 1 minute it's 6 seconds, after 1 hour it's 6 minutes etc...

Some solution is setting repeat duration little bit shorter, so it's not late at required tick, for an example that works and then scheduler repeats tasks as required:

Cancellable task = Akka.system().scheduler().schedule(
        Duration.create(0, TimeUnit.MILLISECONDS),
        Duration.create((1000 - tickerDuration/2), TimeUnit.MILLISECONDS),
        actor, new TickMsg("Tick", 0, 120)
);

Unfortunately this way is little bit uncomfortable and easy to forget, is there any other way to repeat tasks every x seconds (or other TimeUnit) without converting it to milliseconds and shortening?

回答1:

This is fixed in version 2.1 of Akka.

The reason is quite simple: the HashedWheelTimer does not know about repeated tasks, so the task needs to reschedule itself, but since this happens by definition after the tick it will always be late and fall into the next bucket. The fix was to include a drift correction, see here for the details.