PerMalmberg/libcron

`now = last_tick` in Cron::tick()

Closed this issue · 2 comments

Regarding the following logic in Cron::tick():

        if(!first_tick)
        {
            // Only allow time to flow if at least one second has passed since the last tick,
            // either forward or backward.
            auto diff = now - last_tick;

            constexpr auto one_second = std::chrono::seconds{1};

            if(diff < one_second && diff > -one_second)
            {
                now = last_tick;
            }
        }

The method as written will query every task in the queue for expiration on every call, but this logic just makes it reuse an old timestamp for some reason that isn't captured in the comments.

What problem is this logic trying to solve?

Is there a reason that tick() shouldn't just abort further processing when called twice within a span of one second?

It looks like the logic was added in this commit: efeb1e4

Comment suggests that it is needed to prevent a task from being executed multiple times when tick() is called more than once during the same second.

This seems like a really odd case. If the task already executed, it should have recalculated a new execution time, so what are the circumstances in which the issue would occur?

The only thing I can think of would be a one-shot event scheduled for a particular time, but then why is it still in the queue after it got executed on the previous tick?

...or is it maybe concerned with the case of a 1Hz task being sometimes executed more than once per elapsed second, when the wall clock second has advanced since the last call to tick()?

Hi, sorry for the late reply, currently on vacation.

It's been five years since I wrote this code, but based on the test it seems to me that calling tick(), which drives the entire machine, multiple times during the same second would cause the task to be executed twice.

The minimum resolution is one second and a task scheduled to run every second would reschedule itself to the same second, thinking it wouldn't be called again until at least a minute has passed. However, if tick is called multiple times during that second, the schedule will match and thus trigger the task again.