Stability & Scaling

Magento Cron Health as an Early Warning Signal

When Magento cron falls behind, indexing, email, and cleanup all degrade quietly. Read cron health from the cron_schedule table before customers notice.

Jason Schuman · March 18, 2026

Cron is the heartbeat, and it fails quietly

Magento depends on cron for work customers never see directly: reindexing, sending email, cleaning expired quotes, generating catalog price rules, and flushing caches on schedule. When cron is unhealthy, all of that degrades at once.

The failure is quiet. The storefront keeps serving pages while indexes go stale and emails stop sending, so nobody notices until a customer does.

This article shows how to read cron health from one table, what each failure state means, and why the cron_schedule table itself is often the first visible symptom.

What cron actually runs

Magento organizes scheduled work into groups, chiefly default, index, and consumers. Each group runs on its own cadence and records every job in the cron_schedule table.

One crontab line drives all of it, usually * * * * * php bin/magento cron:run, installed with bin/magento cron:install. If that line is missing or the process cannot run, everything downstream stops.

The one query that shows cron health

You do not need a monitoring tool to see whether cron is healthy. Group the schedule table by status:

SELECT status, COUNT(*) FROM cron_schedule GROUP BY status;

On a healthy store the counts are dominated by success, with a small number of pending jobs waiting their turn. Any other shape is a signal worth chasing.

What each failure state means

The status column is the whole diagnosis. Each value tells you something different:

  • A pile of missed jobs means cron is not running often enough, or not running at all, to keep up with the schedule.
  • Rows stuck in running that never resolve usually mean a job was killed mid-execution, often by a PHP memory limit or a deploy.
  • A growing backlog of pending means jobs are being scheduled faster than they finish.
  • Repeated error rows point at one specific job failing every run, which the job_code column names exactly.
A stuck running row that never flips to success or error is not a job still working. It is almost always a job that was killed and will never report back.

Finding the exact job that failed

Once the status counts show a problem, one more query names the culprit. Filter to the failing states and read the job_code:

SELECT job_code, status, scheduled_at, executed_at
FROM cron_schedule
WHERE status IN ('running', 'error')
ORDER BY scheduled_at DESC
LIMIT 20;

A single job_code repeating across the failures tells you which feature is broken. An index job points at reindexing, a consumers job points at message-queue work, and a custom job_code points straight at the extension that registered it.

When cron_schedule bloats, read it as a symptom

The cron_schedule table should stay small, because Magento prunes its own history. When it holds hundreds of thousands of rows, that maintenance is not running correctly.

That growth is often the first thing an audit notices, since a bloated cron_schedule is easy to see and points straight at the cron problem behind it. The bloat is the smoke. The failing scheduler is the fire.

How often cron needs to run

The standard cadence is once a minute, which is what the * * * * * crontab entry provides. That does not mean every job runs every minute, because each job carries its own schedule inside Magento.

What the every-minute run guarantees is that Magento gets a chance to check what is due and dispatch it. Drop that cadence to every five or ten minutes and jobs start piling into missed, because the scheduler is not getting the chances it expects.

The usual root causes

Most cron problems come down to a short list. Working through it resolves the majority of cases:

  • Cron is not installed in the system crontab at all, so nothing runs.
  • Cron runs as the wrong system user and cannot write to var/ or generated/.
  • Jobs exceed the PHP CLI memory limit and are killed partway, leaving running rows behind.
  • Overlapping cron:run processes collide because a previous run never finished.

Each of these is straightforward to confirm once the status counts tell you which direction to look.

Reading cron as an early-warning system

Cron health predicts problems that have not surfaced yet. Stale indexes, unsent order emails, and quote tables that never get cleaned all trace back to it.

Checking the status counts takes a minute and tells you whether the platform's background work is keeping up. When it is not, you have found a problem before your customers do, which is the entire point of a health review.

The cheapest version of this is a scheduled query. Counting missed and error rows once a day, and alerting when either climbs, catches a failing scheduler within hours instead of at the next stale-index complaint.

None of this requires new tooling. It only takes the discipline to look at a table the store already maintains for you.