cron_schedule 中大量任务变成 missed,与 error 不是同一种故障。error 表示任务已经开始执行并抛出错误;missed 通常表示调度器发现这条计划时,它已经超过允许启动的时间窗口。要解决问题,必须判断计划有没有按时生成、系统 Cron 有没有按分钟启动、以及前一批任务是否把进程堵住。
先看一段完整时间线
SELECT schedule_id, job_code, status, scheduled_at,
executed_at, finished_at, messages
FROM cron_schedule
WHERE scheduled_at > NOW() - INTERVAL 2 HOUR
ORDER BY schedule_id DESC;
如果完全没有未来的 pending 记录,计划生成器没有正常运行;有 pending 但没有 executed_at,系统 crontab 或 Cron 进程可能没有启动;前面大量 running 且长期没有 finished_at,则要查长任务和锁。
单看一条 missed 没有意义。比较同一 job_code 连续多条记录,确认是所有组同时中断,还是只有 index、consumers、default 或自定义组异常。
系统 crontab 必须使用正确的 PHP 与文件用户
crontab -l
php -v
php --ini
bin/magento cron:run
Web PHP 与 CLI PHP 版本、扩展和 php.ini 可能不同。计划由错误用户执行时,会出现 var、generated、日志或锁文件权限问题。不要用 root 长期运行 Magento Cron 来绕过权限,它会继续生成 Web 用户无法写入的文件。
一个慢任务能拖垮同组后续任务
导入、邮件、第三方同步或全量数据处理如果没有批次和超时控制,可能长期占用 Cron 组。查看进程、PHP-FPM/CLI 资源和任务日志,找出最早开始却未结束的 job。自定义任务应避免一次读取全部集合,使用分页或游标,并记录每批进度。
需要隔离时,可为重要 Cron group 配置独立进程。但独立运行并不等于可以忽略并发锁;同一任务如果上一次还没结束,下一次又启动,可能重复发送、重复导入或争用数据库。
服务器时间和配置窗口也会制造 missed
操作系统时区、数据库时间与 Magento 配置不一致时,排查会非常混乱。scheduled_at 通常按数据库时间记录,后台显示还可能转换时区。同步 NTP,并比较:
date
php -r 'echo date("c"), PHP_EOL;'
mysql -e 'SELECT NOW(), @@system_time_zone, @@session.time_zone;'
Cron 组中的 schedule_generate_every、schedule_ahead_for 和 schedule_lifetime 决定生成频率、提前量与错过窗口。不要为了隐藏 missed 就无限增大 lifetime;这会让本应过期的任务在很晚之后集中执行。
清理历史 cron_schedule 记录可以改善表大小,但不能修复调度链路。恢复后观察至少两个完整周期,确认未来计划持续生成、pending 能转为 success,且积压数量不再增长。对订单邮件、索引和队列消费者还要验证业务结果,而不是只看状态变绿。

