Reason 1: UTC timezone
Timezones can always be a bit of a headache when it comes to scheduled tasks and server locations. Magento stores it’s cron tasks in UTC, but checks the locale of your (admin) store to see if the time has already passed. Therefore it is advised to set the time of your store to UTC, but the time of your separate websites/store views respectively to their locale.
Reason 2: The 'missed if not run within' -parameter
If you want to know how Magento determines if a task is ‘too late for the schedule’ take a look at Mage_Cron_Model_Observer::_processJob()
. This is the part of the code that is responsible for the message:
$scheduleLifetime = Mage::getStoreConfig(self::XML_PATH_SCHEDULE_LIFETIME) * 60;
$now = time();
$time = strtotime($schedule->getScheduledAt());
if ($time > $now) {
return;
}
...
if ($time < $now - $scheduleLifetime) {
$errorStatus = Mage_Cron_Model_Schedule::STATUS_MISSED;
Mage::throwException(Mage::helper('cron')->__('Too late for the schedule.'));
}
...
// (execute the chain of tasks)
The self::XML_PATH_SCHEDULE_LIFETIME
-parameter is the ‘missed if not run within’-value which is set in the configuration in 'System > Config > Advanced > System > Cron':
The code itself is pretty self-explanatory:
- It takes the time of the scheduled tasks.
- If the time of the scheduled task is in the future it does nothing.
- If the time of the scheduled task is in the past (=older than the current timestamp minus the 'missed if not run within'-value) it throws the error.
- Otherwise it just runs the task as required.
Effectively, when the ‘missed if not run within’-parameter is set to 15 minutes, this means that if the scheduled task is older than now – 15 minutes, it will not run, but instead throw this error. Needless to say, when this value is lower than the time your cron runs (for example: if your cron runs every 5 minutes, but this value is set to 2 minutes), this will obviously throw this error.
You probably didn’t do this, but it is good to know this inner mechanic of how Magento handles crons. Especially the part that Magento checks the schedule prior before running any tasks. And in the next reason I’ll explain to you why:
Reason #3: External plugins
This is the part where I was pulling my hairs. My timezone was correct, my configuration was correct, but my cron schedule was still showing the ‘too late for the schedule’-message. So what was happening?
On further inspection, I noticed that there were some tasks from external plugins who where starting (the executed_at -column in the database revealed this), but were never finishing (the finished_at -column stayed NULL for these tasks). So something was preventing these tasks from being finished (probably causing a crash in PHP or something) and therefore stopping the entire chain of tasks!
The next logical thing that happened of course, was that after 3 tries (15 minutes later), the time for all the scheduled tasks that where further on in the chain all became too late. Too late for the schedule to be exactly. Up until the task that was causing the problems itself also became too late.
So how did I solve this?
Well, in my case I had to debug and fix the tasks of 2 external plugins that were throwing notices and warnings. For some reason even a notice or a warning (so not just an exception) caused my cron to fail silently. Perhaps the fact that I was on HHVM instead of PHP had something to do with this, but I’m not sure (yet).
In conclusion
After you did an investigation and it still not working. You can try increase your PHP memory_limit
.
UPDATED
In AOE Scheduler I was seeing weird bars where it looked like a certain cron was running for a really long time but according to logs they were only running for a second or so. I checked in that cron and it had the code:
date_default_timezone_set('Australia/Brisbane');
The cron itself was overriding the Magento timezone which was causing following cron tasks to think they'd missed their chance to run..
Hope it helps.