Magento’s cron is the quiet engine behind indexing, sitemap generation, abandoned cart emails, currency rates and dozens of other jobs. When it stops - and it stops silently - the symptoms appear days later as stale prices, missing orders in reports and unsent emails. Understanding the cron system properly is basic hygiene for every Magento store.
How Magento Cron Works
Magento registers its own crontab entry which runs bin/magento cron:run every minute. Each run consults the cron_schedule database table: jobs due are executed, jobs finished are marked, jobs stuck are eventually marked as error. Jobs belong to groups - principally default, index and consumers - each with its own process.
Check your crontab has all three:
* * * * * /usr/bin/php /var/www/html/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /var/www/html/var/log/magento.cron.log
* * * * * /usr/bin/php /var/www/html/update/cron.php >> /var/www/html/var/log/update.cron.log
* * * * * /usr/bin/php /var/www/html/bin/magento setup:cron:run >> /var/www/html/var/log/setup.cron.log
Reading cron_schedule
The table tells you everything about cron health:
SELECT job_code, status, COUNT(*) AS n, MAX(executed_at) AS last_run
FROM cron_schedule
GROUP BY job_code, status
ORDER BY last_run DESC;
A wall of running rows older than an hour means jobs are dying mid-flight - usually memory limits or fatal errors. A wall of pending rows in the past means cron is not running at all or cannot keep up.
The Failures We See Most
- Cron not installed after a migration: the classic.
crontab -lon the new server, every time. - Wrong PHP binary: cron must use the same PHP version and configuration as the web process; a CLI on PHP 7.4 against a PHP 8.3 codebase fails instantly.
- Memory exhaustion: index jobs on large catalogs need generous
memory_limitin the CLI php.ini. - Stale locks: a crashed job can leave a lock that blocks its group; clearing
cron_schedulerows with statusrunningthat are hours old usually releases it.
Long-Running Jobs and Consumers
Queue consumers (RabbitMQ or the database queue) are managed by cron too, via the consumers group. If you use asynchronous operations - bulk APIs, MSI async stock, export - make sure consumers_runner runs and max_messages is tuned so consumers restart periodically rather than leaking memory forever.
Monitoring That Actually Helps
- Alert when
MAX(executed_at)for critical jobs (indexer_reindex_all_invalid,sales_send_order_emails) is older than a few minutes - Alert on
errorstatus counts - Log cron output to files and rotate them
Cron is unglamorous, but almost every “mystery” Magento incident - unsent emails, stale stock, missing invoices - traces back to it. Instrument it once, alert on it forever, and it will never bite you again.