计划好的文章到点还是「定时」状态、备份插件说的「每日邮件」半天没到、WooCommerce 里一堆「计划中」的订单操作迟迟不动------后台能进,前台也能打开,但 到点该跑的事没跑 。这和今天写过的数据库连不上、表单 SMTP、HTTPS 重定向环、整站严重错误、结账转圈、媒体库上传失败不是一类故障:站点活着,卡在 WP-Cron / 计划任务触发链路 (访客或系统 Cron 去敲 wp-cron.php → 回环请求能通 → 事件真正执行;Woo 还多一层 Action Scheduler 队列)。
更稳的顺序是:先看 工具 → 站点健康 里「计划事件」与「能否完成回环请求」→ 用 WP-CLI 只读核对 wp cron test / wp cron event list → 再查回环被 Basic Auth、安全插件、缓存/CDN 拦 wp-cron.php → 确认是否写了 DISABLE_WP_CRON 却没接系统 Cron → 最后才看 Action Scheduler 积压与单个 hook 是否超时。别一上来就批量删 cron 事件,也别在生产上盲目 wp cron event run --due-now。
先分清:触发不足 vs 回环被拦 vs 已禁用无替代 vs 队列积压 vs 任务超时
「定时不跑」常见落在五条线上,别混着改:
- 触发不足(流量型 WP-Cron):默认靠有人访问站点时顺带触发。低流量站、整站静态化、强缓存把几乎所有请求挡在边缘时,到期事件会一直挂着「该跑却没人敲门」。
- 回环(loopback)被拦 :WordPress 需要自己请求自己的
wp-cron.php(或 admin-ajax 相关路径)。站点前面挂了 HTTP Basic Auth、错误的防火墙规则、安全插件拦内网/本机 IP、或强制把回环打到公网又被 WAF 打回,表现就是站点健康里回环失败、计划事件堆积。 DISABLE_WP_CRON已开、系统 Cron 没接上 :wp-config.php里禁用了内置触发,却忘了 crontab / 面板计划任务去 curl/wgetwp-cron.php,或 URL、PHP 用户、间隔写错------等于彻底没人触发。- Action Scheduler / Woo 计划操作积压:WooCommerce、邮件、订阅类插件大量用 Action Scheduler(自定义表 + runner)。WP-Cron 本身可能是好的,但队列里 pending/failed 很多,或 runner 被关掉、被对象缓存拖住。
- 单个任务本身超时 / Fatal :触发与回环都正常,但某个 hook(大备份、全量同步、生成报表)跑到一半 PHP
max_execution_time/ 内存爆掉,后续同组任务被拖死。要看该 hook 的日志,而不是只改 Cron 开关。
先记下:站点健康原文、是否存在 DISABLE_WP_CRON、最近到期未跑的事件名、以及(若装了 Woo)Action Scheduler 里 pending 数量。再决定是修回环还是改系统 Cron。
第一步:站点健康 + 只读核对 WP-Cron(别先改配置)
用管理员打开 工具 → 站点健康 → 状态 / 信息:
- 看是否提示 计划事件延迟 、无法完成回环请求、或 REST/HTTP 相关失败。回环失败时,先别急着加系统 Cron------内置触发即使「有人访问」也可能敲不响自己。
- 在 信息 → 服务器 / WordPress 记下时区、
DISABLE_WP_CRON(若页面有展示)、以及对象缓存是否启用(部分环境下会影响瞬时锁与队列感知)。 - 有 WP-CLI 时,在站点根做 只读 核对(不跑事件、不删事件):
bash
# 测试 WP-Cron 生成器能否工作(只读探测,生产可跑)
wp cron test
# 列出已注册事件:看 hook、下次运行时间、是否已 overdue
wp cron event list --fields=hook,next_run_relative,recurrence
# 可选:只看已到期仍挂着的
wp cron event list --fields=hook,next_run,next_run_relative | head -n 40
解读要点:
wp cron test失败 → 优先第二步回环 / HTTP 可达性,而不是先改业务插件。- 列表里大量
next_run_relative为「已过期 X 小时/天」→ 触发或回环长期异常;记下重复出现的 hook(如publish_future_post、备份插件名、Action Scheduler 相关),后面第三、四步对症。 - 不要 在这一步执行
wp cron event delete批量清理,也 不要 无名单地wp cron event run --due-now:未知 hook 可能触发大规模同步、邮件轰炸或锁表。若必须手动跑,先--due-now前用event list确认 hook,再对 单个 hook 执行wp cron event run <hook>,并在低峰、有备份时做。
浏览器侧可临时开无痕访问前台一次,再刷新事件列表,看「纯流量触发」是否能动一点点;若完全不动,更像回环或已禁用内置 Cron。

第二步:回环、Basic Auth、安全插件、缓存是否拦了 wp-cron.php
触发依赖「站点能请求到自己」。逐项核对:
- HTTP Basic Auth / 整站密码门 :开发或临时防护常加在 Nginx/Apache。访客浏览器会弹窗,但 PHP 回环请求默认不带账密 →
wp-cron.php401。处理:对wp-cron.php(及必要的 admin-ajax)单独放行,或给回环配置授权头;排障对比时可短时去掉 Auth 测一次,测完记结果并恢复。 - 安全插件 / 主机 WAF / 防火墙 :查封锁日志里是否出现
wp-cron.php、本机 IP、127.0.0.1、或服务器公网 IP 访问自己。对 Cron 路径做放行对比(只改一条规则),确认误杀后再留白名单,不要为了跑定时长期关掉整站防护。 - 缓存插件 / CDN / 全页静态 :若把
wp-cron.php也缓存成 200 空壳,或边缘把带doing_wp_cron的请求错误改写,事件不会真正执行。规则上应 排除wp-cron.php,并避免对 Cron 查询串做错误的缓存键合并。 - HTTPS / 反代头 :站点 URL 是 https,回环却因证书、错误的
X-Forwarded-Proto、或内网仍走 http 被强制跳转,可能变成重定向环或证书校验失败。这与「整站太多重要定向」相关但场景更窄:只影响自请求。 - DNS / hosts:容器或多机部署时,域名解析到公网 VIP,回环出网再回来被安全策略打掉;可评估是否让应用容器解析到内网 upstream(改动前先在预发验证)。
命令行快速探一下(在服务器上,把域名换成自己的):
bash
# 看状态码;401/403/301 连环都值得警惕
curl -sI "https://example.com/wp-cron.php?doing_wp_cron"
# 若前面有 Basic Auth,对比带用户与不带用户的差异(账密勿写进文章仓库)
# curl -sI -u 'USER:PASS' "https://example.com/wp-cron.php?doing_wp_cron"
回环与触发都依赖「服务端能否及时响应自请求」。若站点 TTFB 极差、PHP-FPM 队列长期打满,Cron 也会表现为「偶发到期未跑」------这类要和服务端性能一起看,而不是只改 crontab 间隔。可参考 服务端瓶颈排查里关于计划任务的一节,把慢回环和计划任务延迟放在同一条链路上核对。
第三步:DISABLE_WP_CRON + 系统 Cron 的正确接法与验证
低流量站、或回环在架构上不稳时,生产更常见的做法是:关掉内置触发,改由系统 Cron 定时打 wp-cron.php。
在 wp-config.php 里(写在「That's all, stop editing!」之前):
php
define( 'DISABLE_WP_CRON', true );
然后在系统 crontab(或主机面板「计划任务」)用 运行 PHP 的同一用户 添加,例如每 5 分钟:
cron
*/5 * * * * curl -fsS -o /dev/null "https://example.com/wp-cron.php?doing_wp_cron=$(date +\%s)"
或用 wget:
cron
*/5 * * * * wget -q -O /dev/null "https://example.com/wp-cron.php?doing_wp_cron=$(date +\%s)"
注意点:
- 先写系统 Cron,再开
DISABLE_WP_CRON(或同一变更窗口内完成两者)。只禁用内置、未接替代 → 定时全停。 - URL 必须是站点真实可访问地址(含 https、正确域名);多站点注意网络主站与子站触发策略是否符合文档预期。
- 间隔不必超短:1 分钟一次通常没必要,徒增 PHP 压力;5 分钟对多数发布/备份足够。备份类重任务仍应在插件侧错峰,而不是把 Cron 打到每分钟。
- 面板「PHP 脚本」类计划任务:工作目录、
php二进制版本要与站点一致;用 CLIwp cron event run做系统任务可以,但同样 禁止 无筛选地跑全部 due 事件当日常方案------日常仍优先敲wp-cron.php,让核心按锁与顺序调度。 - 验证:等一个间隔,看
wp cron event list里过期事件是否减少;再设一篇 10~15 分钟后的定时草稿,看是否准时变「已发布」。备份邮件则看下一封是否在预期窗口到达(还要结合 SMTP,那是另一条链路)。
回滚:去掉或注释 DISABLE_WP_CRON,删掉对应 crontab 行,清 opcode 缓存后用站点健康再测回环。两边不要长期「双开又双关」状态不清------变更说明里写清当前以哪一种触发为准。
第四步:Action Scheduler / Woo 计划操作积压怎么看
WooCommerce 及相关插件大量依赖 Action Scheduler。WP-Cron 正常仍可能出现「订单计划状态不更新、邮件延后、订阅续费没扣」:
- 后台进入 WooCommerce → 状态 → 计划操作(或插件提供的 Action Scheduler 菜单):看 Pending、In-progress、Failed 数量与最老 pending 的时间。
- Pending 长期增长:runner 没被触发(回到第一~三步)、或每次 runner 处理条数不够、或某个失败任务反复占坑。
- Failed:点开参数与错误信息,常见是支付回调类 hook、邮件、第三方 API 超时。先修失败原因,再考虑重试;不要无差别批量清空所有 pending。
- 对象缓存 / Redis 异常时,偶发出现锁未释放、runner 以为自己在跑。排障时可在低峰对照「关对象缓存短测」与日志,确认后恢复缓存并修根因。
- WP-CLI(若环境有 Action Scheduler 命令)以只读列表、单条重试为主;大规模
run同样要在低峰、有监控时做。
这一步的目标是区分:时钟没敲响 (WP-Cron)还是 敲响了但队列消化不动(Action Scheduler)。两者一起坏时,先让 Cron 稳定,再清队列,否则边修边积压。
验证与回滚
建议验收动作(同一维护窗口):
wp cron test成功;或系统 Cron 触发后访问日志里能看到定期的wp-cron.php200(非 401/403/缓存壳)。- 故意设一篇 10~15 分钟后的定时文章 → 到点变为已发布;或确认
publish_future_post不再长期 overdue。 - 备份/邮件类:下一窗任务有日志或邮件到达(若仍无邮件,再查 SMTP,勿与 Cron 混治)。
- Woo:计划操作 Pending 不再单调上涨;抽一条业务相关 pending 能在合理时间被消化。
- 回滚策略:
DISABLE_WP_CRON与 crontab 成对回退;WAF/Basic Auth 放行规则可单条撤销;不要靠批量删除 cron 事件「凑成功」;临时打开的调试日志及时关掉。
排障窗口尽量短;确认稳定后把 crontab、是否禁用内置 Cron、回环放行规则写进运维备忘,避免下次有人只改 wp-config 半截。
验收清单(技术)
- 站点健康:计划事件 / 回环结论已记录;与
DISABLE_WP_CRON状态一致 -
wp cron test与wp cron event list(只读)已看;过期 hook 已记下,未批量 delete、未盲目--due-now - Basic Auth / 安全插件 / 缓存 / CDN 未误杀
wp-cron.php;curl 探活状态码正常 - 若禁用内置 Cron:系统 crontab(或面板任务)URL、用户、间隔正确,且变更窗口内成对生效
- Action Scheduler / Woo 计划操作:Pending/Failed 可解释;队列问题未与「Cron 完全没触发」混治
- 定时稿或等价业务事件已复测到点执行;临时放行与调试项已收紧并写回滚说明