Skip to content
Magento 211 min de leitura

Cron do Magento 2: o que monitorar, como configurar, como evitar travar

Cron do Magento 2 é a coluna vertebral da loja — sem ele, indexers não atualizam, pedidos não mudam de status, integrações ficam paradas. Este é o conjunto de práticas que evita o ciclo "loja parece bem, mas pedidos estão sumindo".

Linhas de código em editor com tema escuro
Cron é a coluna vertebral do Magento 2 — sem ele, indexers não atualizam, pedidos não mudam de status, integrações ficam paradas.Unsplash
O que você vai aprender
  • Por que ~40% dos bugs reportados de Magento 2 em produção têm raiz no cron.
  • Como saber em < 2 minutos se o cron está rodando, atrasado ou travado.
  • Os 3 grupos de cron e por que rodar todos no mesmo processo é receita pra travamento.
  • Pid-lock, supervisor, e a rotina de purge de cron_schedule.

Se você opera Magento 2 e ainda não passou pela frase "acho que o cron travou", ou ele está travado agora e você não sabe, ou opera uma loja muito pequena. Cron é a coluna vertebral do Magento 2: sem ele, indexers não atualizam, pedidos não trocam de status, e-mail de boas-vindas não sai, sitemap não regenera, integrações ficam paradas. Este guia é o conjunto de práticas que evita o ciclo de "loja parece bem, mas pedidos estão sumindo".

~40%
dos issues de Magento 2 em produção (forum/Stack) têm raiz em cron travado/atrasado
Análise empírica — Magento Stack Exchange
3 grupos
de cron no Magento 2 (default, index, consumers) — cada um deve rodar em processo separado
Adobe Commerce DevDocs
~1.5 GB
é o tamanho típico da tabela cron_schedule em loja sem purge, após 1 ano
Observação setorial
15 min
é o ciclo padrão de "schedule" do cron — qualquer jitter acima de 5 min indica gargalo
Magento default config

O que o cron do Magento 2 faz

Diferentemente de cron Unix tradicional, o Magento 2 tem seu próprio agendador baseado em banco. O cron Unix invoca php bin/magento cron:run a cada minuto, e o Magento internamente:

  1. Lê a tabela cron_schedule (jobs agendados).
  2. Identifica os que estão prontos para executar (status = 'pending').
  3. Trava cada um (status = 'running'), executa, e marca como 'success' ou 'error'.
  4. Limpa jobs antigos (em teoria, mais sobre isso adiante).

3 grupos distintos:

GrupoO que rodaFrequência típica
defaultJobs de negócio: cancelamento de pedido, e-mail, sitemap, currency rate, statistics, customer_notificationA cada 1 min, jobs com periodicidade variável
indexReindex incremental (catalog, search, inventory, etc.)A cada 1 min para jobs em "Update by Schedule"
consumersProcessa mensagens da fila (queue) — async tasks como atualizar Elasticsearch, processar pedido pesado, etc.Contínuo (worker pool)
📌 Por que isso importa: rodar os 3 grupos no mesmo processo cron é a fonte número um de travamento. Um job pesado de index bloqueia o default, que bloqueia atualização de status de pedido — e cliente fica com pedido em "processing" eterno.
Mesa de trabalho com laptop e anotações de planejamento
Rodar os 3 grupos de cron no mesmo processo é a fonte número um de travamento — um job pesado bloqueia todos os outros.Unsplash

Setup recomendado em produção

Em vez do clássico:

# CRONTAB ANTIGO — RUIM em produção
* * * * * cd /var/www/magento && php bin/magento cron:run

Use processos separados:

# CRONTAB MODERNO — 1 entrada por grupo, com lock
* * * * * /usr/bin/flock -n /tmp/m2-cron-default.lock /var/www/magento/bin/magento cron:run --group=default
* * * * * /usr/bin/flock -n /tmp/m2-cron-index.lock /var/www/magento/bin/magento cron:run --group=index

Para os consumers, use supervisor ou systemd — não cron:

# /etc/supervisor/conf.d/magento-consumers.conf
[program:magento-consumer-async-operations]
command=php /var/www/magento/bin/magento queue:consumers:start async.operations.all --max-messages=1000
autostart=true
autorestart=true
user=magento
numprocs=1
stdout_logfile=/var/log/magento/consumer-async-ops.log
The single biggest improvement you can make to Magento 2 stability is splitting the cron groups into separate processes with locks.— Vinai Kopp, Magento Core Contributor

Diagnóstico rápido: o cron está saudável?

Check 1 — Algum job está rodando há mais de 30 min?

SELECT job_code, status, scheduled_at, executed_at,
       TIMESTAMPDIFF(MINUTE, executed_at, NOW()) AS minutes_running
  FROM cron_schedule
 WHERE status = 'running'
   AND executed_at IS NOT NULL
 ORDER BY executed_at ASC;

Se aparecer job rodando há > 30 min, está travado. Mate o processo (ps aux | grep cron:run, depois kill) e force o status para'error' manualmente — caso contrário o Magento espera ele "terminar" indefinidamente.

Check 2 — Backlog de jobs "missed"

SELECT job_code, COUNT(*) AS missed
  FROM cron_schedule
 WHERE status = 'missed'
   AND scheduled_at > NOW() - INTERVAL 7 DAY
 GROUP BY job_code
 ORDER BY missed DESC;

"missed" significa que o job foi agendado mas não executou na janela permitida — o cron estava ocupado ou parado. Mais que ~50 por dia em qualquer job é sinal vermelho.

Check 3 — Tabela cron_schedule não está inflando?

SELECT COUNT(*) FROM cron_schedule;
-- > 200.000 = purge agressivo está falhando

Purge da tabela cron_schedule

Em teoria, Magento purga jobs antigos automaticamente. Em prática, em loja com muitos jobs e custom modules, esse purge frequentemente nunca acontece — e a tabela cresce até travar o cron.

Configuração em Stores → Configuration → Advanced → System → Cron:

  • History Cleanup Every: 60 min (ok)
  • Success History Lifetime: 1440 min (1 dia) — pode reduzir para 360 min em loja grande
  • Failure History Lifetime: 10080 min (7 dias) — útil para debug

Se mesmo assim a tabela inflar, force purge manual:

DELETE FROM cron_schedule
 WHERE created_at < NOW() - INTERVAL 7 DAY
   AND status IN ('success', 'error', 'missed');

-- Em loja grande, faça em lotes para não lockar:
DELETE FROM cron_schedule
 WHERE created_at < NOW() - INTERVAL 7 DAY
   AND status IN ('success', 'error', 'missed')
 LIMIT 50000;

A parte de queue consumers que cobre 80% dos "pedidos sumindo"

Em Magento 2 moderno (2.4+), boa parte do que parece "cron travado" é na verdade consumer travado. Os consumers processam:

  • async.operations.all — operações bulk (import/export, mass actions)
  • product_action_attribute.update — update em massa de atributo
  • inventory.indexer.source.item — sincronização de MSI
  • sales.rule.update.coupon.usage — uso de cupom

Veja a fila atual:

SELECT topic_name, COUNT(*) AS pendentes
  FROM queue_message qm
  JOIN queue_message_status qms ON qm.id = qms.message_id
 WHERE qms.status = 4  -- NEW (não processado)
 GROUP BY topic_name
HAVING pendentes > 50
 ORDER BY pendentes DESC;

Mais de 50 mensagens "NEW" em um tópico, e crescendo nos últimos 15 minutos, é consumer travado. Veja o detalhe completo em pedidos travados no Magento 2.

Calendário pendurado em parede de escritório
Purge agressivo evita que a tabela cron_schedule passe de 200 mil linhas — onde o próprio cron começa a engasgar.Unsplash

Monitoramento contínuo do cron

O monitoramento mínimo do cron tem 4 sinais — qualquer um disparando é alerta:

  1. Job rodando há > 30 min em status running.
  2. Job sem nenhuma execução nos últimos 30 min quando deveria rodar a cada 15 (e.g. indexer_update_all_views).
  3. Tópico de queue com > 50 NEW e crescendo há 15 min.
  4. cron_schedule com > 200k linhas — purge não está rodando.

Datadog, New Relic ou um cronjob próprio que rode esses checks e dispare webhook para Discord/Slack atende perfeitamente. A Especialista Loja Virtual tem isso como teste pré-configurado para Magento — basta apontar a credencial.

Erros comuns que matam o cron

⚠ Os 5 anti-padrões mais frequentes:
  1. Rodar todos os grupos no mesmo processo cron (sem --group).
  2. Sem flock — duas instâncias concorrentes corrompem cron_schedule.
  3. Permissões erradas — cron rodando como root, gerando arquivos que o php-fpm não consegue ler depois.
  4. Custom module com cron.xml mal escrito — schedule errado, ou job sem catch de exception, derrubando todo o grupo.
  5. Consumer sem --max-messages — memória vaza ao longo do tempo, processo morre e supervisor reinicia, perdendo mensagem in-flight.

Checklist final

  1. Crontab separado por --group com flock ativo.
  2. Consumers via supervisor com --max-messages e autorestart=true.
  3. Purge de cron_schedule funcionando (tabela < 200k linhas).
  4. Monitoramento dos 4 sinais ativo, com alerta em Slack/Discord.
  5. Logs de consumer indo para /var/log/magento/, com rotação.
  6. Indexers em "Update by Schedule", não "Update on Save" (este último derruba performance).
  7. Custom cron.xml revisado — todo job com try/catch e logging.
✓ Próximo passo: rode agora as 3 queries de diagnóstico (rodando há > 30min, missed nos últimos 7 dias, tamanho da tabela). Provavelmente vai encontrar pelo menos um sinal vermelho.

Referências

  1. Adobe Commerce. Configure and run cron — official guide. experienceleague.adobe.com/en/docs/commerce-operations/configuration-guide/cli/configure-cron-jobs
  2. Adobe Commerce DevDocs. Manage message queues. developer.adobe.com/commerce/php/development/components/message-queues
  3. Vinai Kopp. Magento Cron — A Deep Dive. vinaikopp.com
  4. Mageplaza / Mark Shust. Magento 2 Cron Best Practices — vídeo-aulas e artigos da comunidade.
  5. Linux man-pages. flock(1) — manage locks from shell scripts. man7.org/linux/man-pages/man1/flock.1.html

Perguntas frequentes

Posso rodar todos os grupos de cron com um único bin/magento cron:run?
Pode, mas não em produção. Um job pesado de "index" bloqueia o grupo "default", e pedido fica parado em "processing" eterno. Use --group=default e --group=index em entradas separadas do crontab, com flock para evitar concorrência.
Por que minha tabela cron_schedule tem 2 milhões de linhas?
O purge automático parou de funcionar — comum em loja com muitos custom modules. Configure History Lifetime mais agressivo em Stores → Configuration → Advanced → System → Cron e, se preciso, faça purge manual em lotes (DELETE LIMIT 50000).
Consumer trava sozinho. Como reiniciar automaticamente?
Use supervisor ou systemd com autorestart=true e --max-messages=1000 no comando do consumer. Após 1000 mensagens, o processo morre por design e o supervisor reinicia. Isso evita vazamento de memória que mata o consumer depois de algumas horas.

Monitore tudo isso automaticamente

A Especialista Loja Virtual roda navegação real no seu site a cada poucos minutos, alerta no Discord, Slack ou e-mail e mostra screenshot do incidente. Comece grátis.