定时文章到点不发、后台「计划任务」越积越多,或 WooCommerce 相关队列 Pending/Failed 狂涨------这和今天槽位里写过的表单「提交成功但收不到邮件」、「建立数据库连接时出错」、「全站 HTTPS 后仍显示不安全 / 混合内容」,以及登录 Cookie、502/503、PHP 白屏/插件冲突、媒体上传失败、固定链接 404、Woo 支付回调不是一类故障。站点多半能打开、能写文章,卡在 WP-Cron 从未真正跑起来、DISABLE_WP_CRON 与系统 crontab 脱节、时区导致「未来稿」卡住,或 Action Scheduler 积压拖垮计划发布与后台任务。
更稳的顺序是:先分清是 Cron 根本不触发 / 触发了但定时稿卡住 / Action Scheduler 堆积 / 对象缓存与 transient 副作用 → 核 wp-config 与 wp cron event list → 在 DISABLE_WP_CRON 为真时补系统 crontab 或 curl → 再清 Action Scheduler 与定时稿状态。别一上来就装「伪 cron」插件叠床架屋,也别在没备份前批量删 AS 队列。
先分清:Cron 不触发 vs 定时稿卡住 vs AS 积压 vs 缓存副作用
「定时发布不生效 / 计划任务堆积」常见落在四条线上,别和 SMTP、数据库连接、HTTPS 混合内容混着改:
- WP-Cron 从未触发 :默认依赖访客请求捎带跑 cron;站点几乎无真实流量、被全页缓存拦掉
wp-cron.php、或DISABLE_WP_CRON已开却没系统 crontab,事件会一直「到期未跑」。 - Cron 在跑,但定时稿仍 future :时区(
timezone_string/gmt_offset)与服务器时间不一致、编辑器点了「定时」却未真正落到post_status=future、或发布钩子被插件短路。 - Action Scheduler 积压(Woo / 订阅 / 邮件队列常用):Pending、Failed 暴涨;单次 batch 超时、锁未释放、对象缓存异常,表现为后台慢、相关计划任务「看起来死了」。
- 对象缓存 / transient 副作用:cron lock、AS claim 锁、或 transient 被持久对象缓存「粘住」,表现为偶发「有时能跑有时不能」。
- 插件互抢触发权:多个「Heartbeat / 替代 cron / 队列加速」插件同时声明自己是唯一 runner,结果谁都不稳定,或把同一批 due 事件跑多遍。
先记下:DISABLE_WP_CRON 是否为 true、最近有没有真实前台流量、wp cron event list 里 due 事件是否推进、Woo「计划操作」里 Pending/Failed 数量、是否装了超过一个伪 cron 类插件。再决定是改系统 crontab 还是清 AS。
第一步:核 wp-config、WP-Cron 事件与「访客触发」前提
能复现「到点不发 / 任务堆积」的站点上:
- 打开
wp-config.php,确认是否存在define('DISABLE_WP_CRON', true);。为 true 时,WordPress 不会再靠页面访问捎带跑 cron ,必须靠系统 crontab 或外部 HTTP 打wp-cron.php。 - 用 WP-CLI(有权限时):
wp cron event list、wp cron test(若可用),看哪些 hook 已 due、上次 run 时间是否停滞。 - 无 WP-CLI 时:临时用可靠的 cron 管理插件只做只读观察(看事件列表与下次运行),不要同时开多个「替代 cron」插件互抢。
- 默认可视触发路径:有人访问前台/后台时,WordPress 才有机会 spawn cron。全页缓存、CDN 把 HTML 缓存到边缘且从不回源、或站点长期零流量,都会让「到点不发」变成常态。
- 直接浏览器或 curl 访问
https://你的域名/wp-cron.php?doing_wp_cron(注意频率,别当压测),看是否推动 due 事件;若这里能跑而日常不能,基本坐实「缺触发源」。 - 核对服务器时间与 WordPress 设置 → 常规里的时区;
date/ 面板时钟与站点时区差几小时,会直接让「定时」看起来像失灵。 - 若前面有 CDN / 防火墙:确认
/wp-cron.php未被 WAF 误拦、未被强制缓存成 200 空响应;需要时对这一路径设置绕过缓存或不缓存。
预期 :能说清「谁负责触发 cron」;DISABLE_WP_CRON 状态与真实触发方式一致;due 事件在手动触发后有推进。若手动触发后定时稿仍不动,进系统 crontab 与 AS,而不是继续刷新前台碰运气。
第二步:DISABLE_WP_CRON 为真时补系统 crontab(或 curl),并防重复叠加
确认需要「真实时钟触发」而不是访客碰运气时:
- 常见 crontab 行(路径按实际 PHP/WP-CLI 调整),每分钟跑到期事件:
* * * * * cd /path/to/site && wp cron event run --due-now >/dev/null 2>&1- 或
* * * * * curl -s -o /dev/null "https://你的域名/wp-cron.php?doing_wp_cron"(仅在未禁用且适合 HTTP 触发时)
- 不要 同时:未关访客 cron + 多条重叠 crontab + 多个「强制 cron」插件。重复跑会把 CPU 打满,反而拖慢前台------计划任务本身也会变成性能问题。关于 cron 风暴、队列堆积如何抬高 TTFB、拖垮后台响应,可对照 WordPress 性能优化与站点加速 把「触发频率、batch 大小、对象缓存锁」和应用层优化放在同一张清单里核,再决定是降频、拆队列还是先修锁。
- crontab 用户要有读站点文件与跑 WP-CLI/PHP 的权限;容器/面板环境确认任务落在正确机器(别写在已下线的旧主机)。
- 时区:系统
TZ、PHPdate.timezone、WordPress 时区三者对齐;只改其中一处,定时稿「提前/延后一截」很常见。 - 日志:短期内把 cron 输出接到文件,确认每分钟有跑、无 permission denied / PHP fatal;稳定后改回丢弃或轮转,避免日志盘暴涨。
- 生产注意:改 crontab 前记下旧条目;回滚时先停新任务再恢复旧触发方式,避免双轨并行。
预期 :系统级每分钟有稳定触发;wp cron event list 中 due 事件被消费;前台不再依赖「碰一个访客才发稿」。

第三步:Action Scheduler ------ Pending / Failed 积压怎么查、怎么清
WooCommerce、订阅、部分邮件/同步插件把重活丢进 Action Scheduler(后台路径常见为 WooCommerce → 状态 → 计划操作,或独立的 Action Scheduler 屏幕):
- 打开计划操作列表,按状态过滤 Pending / Failed / In-progress,记下数量级与最老任务的 hook 名、预定时间。
- Failed 先看失败原因(timeout、数据库死锁、远程 API 4xx/5xx、内存耗尽),先修根因再重试;盲目「全部重试」只会再次打满队列。
- Pending 长期不降:检查是否有 claim 锁未释放、对象缓存异常、或 cron 根本没跑(回到第一步)。WP-CLI 可用时:
wp action-scheduler相关子命令(版本不同以--help为准)做列表与受控运行,避免在网页点「一次跑一万条」。 - 不要盲目清空表 (如直接 truncate AS 相关表):可能丢支付后置任务、邮件、库存同步。优先取消明确无用的重复 hook、修好失败任务后按批
run。 - 与 WP-Cron 的关系:AS 常依赖 cron 或自身 runner 被触发;只清 AS 界面却不修触发源,Pending 会马上回来。
- 改完保留:截图或导出「hook 名 / 失败信息 / 数量」,便于回滚策略与之后对比。
- 大站点:把「每分钟 due-now」与「AS 大批量 run」错开观察窗口,先确认 cron 触发稳定,再逐步提高 AS 消费吞吐,避免同一分钟内 CPU 与数据库双峰。
预期:Pending 趋势下降;Failed 有明确归因且不再指数反弹;后台「计划操作」页可在合理时间内打开。

第四步:定时发布专病 ------ future 稿、时区与编辑器「立即 / 定时」
Cron 与 AS 都健康、仍有单篇「到点不发」时:
- 在文章列表过滤「定时」或直接查库/
wp post get <ID> --field=post_status,确认状态是future而不是误存成draft/pending。 - 编辑器侧:块编辑器「发布」面板里是「定时」还是别人协作时改成了「立即发布」又撤回;修订记录里看最后一次状态变更时间。
- 时区:设置 → 常规的时区与预期一致;作者按「北京时间 09:00」选的定时,若站点仍是 UTC,会表现为「晚八小时才动」或「好像从没到点」。
- 专用插件/编辑器扩展若接管发布流程,临时禁用后再用原生定时测一篇最小复现稿(标题+一段正文即可)。
- 钩子被短路:主题或插件
remove_action了发布相关 hook,或把future转成私有状态;用健康检查 / 查询监视器看publish_future_post是否在到期后执行。 - 多时区编辑团队:约定「以站点时区为准」写进发布清单,避免每个人按本机时钟估点。
预期 :测试 future 稿在到期后自动变 publish;时区与服务器一致;无插件在到期瞬间把状态改回草稿。
第五步:验证、回滚与验收清单
DISABLE_WP_CRON与真实触发方式一致(访客 / crontab / curl 三选一为主,避免并行风暴)。wp cron event list(或等价 UI)显示 due 事件被定期消费;手动wp cron event run --due-now后列表有变化。- 系统 crontab 仅保留必要条目;无重复
wp-cron.php与 WP-CLI 双轨狂奔;短时日志无 fatal。 - Action Scheduler:Pending 下降趋势可解释;Failed 有根因记录;未擅自 truncate 业务表。
- 至少一篇测试定时稿:到期后前台可见、状态为
publish;时区符合预期。 - 抽检 TTFB / 后台「计划操作」页打开时间,确认修 cron 后没有引入新的队列风暴。
- 回滚预案:保留改前 crontab 原文与 AS 数量截图;若新触发方式异常,先停新任务再恢复旧方式,避免双轨并行。
- 验收只看技术结果(触发、消费、发稿、队列),不把「再装一个伪 cron 插件」当成收尾。
小结
定时发布不生效或计划任务堆积时,按 触发源(WP-Cron / crontab)→ Action Scheduler 积压 → 单篇 future / 时区 → 验证回滚 推进,每次只改一层并保留旧 crontab 与队列快照。把它和 SMTP 投递、数据库连接、HTTPS 混合内容、登录 Cookie、502、白屏、媒体上传、支付回调区分开,能少走很多「狂装伪 cron 插件却越积越多」的弯路。DEVDIY 实务里把「谁触发、谁消费、谁积压」三列记一笔,下次换主机或上 Woo 队列时能直接对备忘,而不是从零猜。