PHP / Magento Dev Blog

  • Home

Magento 2 cron stuck – 50,000 pending jobs and deadlock in cron_schedule

by Henryk Tews / Sunday, 09 August 2026 / Published in Magento / Adobe Commerce

Magento 2 cron stopped working – over 50,000 unexecuted jobs were backed up in the cron_schedule table. Transactional emails were not going out, indexers were not updating, pricing rules were not refreshing. The shop worked normally for customers but was frozen “from the inside”. Fix time: 3 hours.

Symptoms

  • Order confirmation emails stopped arriving
  • Catalog rule prices out of date
  • No entries in var/log/cron.log for several days
  • SELECT COUNT(*) FROM cron_schedule WHERE status = 'pending' returns 52,000
  • System cron entry for Magento is running (crontab -l shows entries)

Diagnosis

bin/magento cron:status

SELECT status, COUNT(*) as cnt
FROM cron_schedule
GROUP BY status
ORDER BY cnt DESC;

SELECT job_code, status, scheduled_at, executed_at, finished_at, messages
FROM cron_schedule
WHERE status != 'pending'
ORDER BY finished_at DESC
LIMIT 20;

ps aux | grep "magento cron"

Cause

One cron job (catalog_product_alert) was entering an infinite loop on a product with corrupted EAV data. The PHP process consumed 100% CPU for tens of minutes, then was killed by the OOM killer. Magento did not mark it as “failed” – the job stayed in “running” status forever. Subsequent cron runs saw the “running” job and did not start new instances.

Solution

bin/magento cron:unlock --all
-- Mark stuck "running" jobs as failed
UPDATE cron_schedule
SET status = 'error', messages = 'Manually unlocked - was stuck in running state'
WHERE status = 'running'
  AND executed_at < DATE_SUB(NOW(), INTERVAL 2 HOUR);

-- Remove backed-up pending jobs
DELETE FROM cron_schedule
WHERE status = 'pending'
  AND scheduled_at < DATE_SUB(NOW(), INTERVAL 1 DAY);

-- Remove old finished jobs
DELETE FROM cron_schedule
WHERE status IN ('success', 'error', 'missed')
  AND finished_at < DATE_SUB(NOW(), INTERVAL 7 DAY);
<?php
class SafeCronJob
{
    public function execute(): void
    {
        set_time_limit(300); // 5 minutes max

        $lastId    = $this->getCheckpoint();
        $processed = 0;

        while (true) {
            $batch = $this->getBatch($lastId, 100);
            if (empty($batch)) break;

            foreach ($batch as $item) {
                $this->processItem($item);
                $lastId = $item->getId();
                $processed++;
            }

            $this->saveCheckpoint($lastId);

            if ($processed % 1000 === 0) {
                sleep(1);
            }
        }
    }
}

Takeaways

The cron_schedule table needs regular cleaning - without it grows to millions of records and itself slows down cron. One stuck job can block all others. Monitoring the number of pending jobs is fundamental - alert threshold: above 500 pending is a signal to investigate.

About Henryk Tews

What you can read next

Xdebug – configuration, PHPStorm, debugging Magento plugins
Strategy pattern in PHP – and how Magento 2 uses it in pricing

© 2026 Created by

TOP
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Always active
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
Zobacz preferencje
  • {title}
  • {title}
  • {title}