Skip to content

Implement catch-up behavior for cron jobs#67

Open
intersel wants to merge 1 commit intoJako:masterfrom
intersel:master
Open

Implement catch-up behavior for cron jobs#67
intersel wants to merge 1 commit intoJako:masterfrom
intersel:master

Conversation

@intersel
Copy link
Copy Markdown

Why it is needed

When there is a server downtime or when the system cron (calling cron.php) is stopped for any reason, scheduled jobs may accumulate delay.

In the current implementation, the next run (nextrun) is always calculated based on the previous nextrun value. If this value is already in the past, the new nextrun can also remain in the past.

This can lead to repeated immediate executions ("catch-up loops") until the scheduler catches up with the current time. In some cases, this may cause unnecessary load or unexpected behavior, especially for jobs that are not designed to run multiple times in quick succession.

This change introduces an option to control this behavior:

  • either keep the existing catch-up mechanism,
  • or reschedule jobs from the current time, avoiding execution of missed runs.

This provides safer and more predictable behavior for most use cases while preserving backward compatibility.

What this PR does

Add a cron_catchup system option to control how missed executions are handled.

When disabled, cronjobs are always rescheduled from the current time, avoiding catch-up loops after downtime.

When enabled, the existing behavior is preserved, with a safeguard against outdated nextrun values to prevent infinite execution loops.

Add a cron_catchup system option to control how missed executions are handled.

When disabled, cronjobs are always rescheduled from the current time, avoiding catch-up loops after downtime.

When enabled, the existing behavior is preserved, with a safeguard against outdated nextrun values to prevent infinite execution loops.
Copy link
Copy Markdown
Owner

@Jako Jako left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is better to calculate the nextrun with a do/while loop until the nextrun is in the future. Then the additional option is not needed.

@intersel
Copy link
Copy Markdown
Author

I get the idea, but wouldn’t this risk shortening the effective interval between runs compared to the configured delay?

@Jako
Copy link
Copy Markdown
Owner

Jako commented Apr 30, 2026

Something like this:

            if ($this->cronmanager->getOption('daylight_saving') && $cronjob->get('minutes') > 60) {
                do {
                    $rundatetime = date('Y-m-d H:i:s', strtotime($cronjob->get('minutes') . ' minutes', (strtotime($rundatetime))));
                } while (strtotime($rundatetime) < time());
                $cronjob->set('nextrun', $rundatetime);
            } else {
                do {
                    $rundatetime = date('Y-m-d H:i:s', (strtotime($rundatetime) + ($cronjob->get('minutes') * 60)));
                } while (strtotime($rundatetime) < time());
                $cronjob->set('nextrun', $rundatetime);
            }

Then the interval between two runs remains the same and just some runs are not executed.

@Jako
Copy link
Copy Markdown
Owner

Jako commented May 5, 2026

Is this code right for you?

@intersel
Copy link
Copy Markdown
Author

intersel commented May 5, 2026

sounds good... not tested yet
Do you want me to redo the PR?

@Jako
Copy link
Copy Markdown
Owner

Jako commented May 5, 2026

It would be nice, if you have time to test the suggested code.

@intersel
Copy link
Copy Markdown
Author

intersel commented May 6, 2026

I'll do my best to give you feedback in the next days...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants