首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >WP-Cron 和系统 cron:触发差异、切换时机与配置步骤

WP-Cron 和系统 cron:触发差异、切换时机与配置步骤

原创
作者头像
用户10345225
发布于 2026-10-25 15:25:49
发布于 2026-10-25 15:25:49
60
举报

WP-Cron 不是常驻定时器。它挂在 WordPress 的 init 上,每次有请求进来时检查一次「有没有到期任务」,有就发一个非阻塞 HTTP 请求去执行 wp-cron.php。没有访客,就没有触发。系统 cron 由操作系统按时间表执行,不依赖网站流量。

判断标准:任务能不能容忍「等下一个访客」?能,继续用 WP-Cron;不能,换成系统 cron。

一、WP-Cron 的触发链路

wp-includes/default-filters.php 里把 wp_cron() 挂到 init:

代码语言:php
复制
add_action( 'init', 'wp_cron' );

wp_cron() 做三件事:检查是否已经在 cron 请求里、检查 DISABLE_WP_CRON、读取 cron 数组找最早的一个到期任务。找到后调用 spawn_cron()。

spawn_cron() 不执行任务,它只是向 wp-cron.php 发一个请求:

代码语言:php
复制
wp_remote_post( $cron_request['url'], array(
    'timeout'   => 0.01,
    'blocking'  => false,
    'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
) );

blocking => false 意味着发出去就不等结果。真正的任务在 wp-cron.php 这个独立的 PHP 请求里跑,它开头会:

代码语言:php
复制
@set_time_limit( 0 );
@ignore_user_abort( true );

然后遍历到期事件逐个执行。

由此带来几个直接后果:

  1. 触发频率等于访客频率。低流量站可能几小时才跑一次。
  2. 请求自己的域名必须成功。DNS 解析、防火墙、HTTPS 证书、内网隔离,任何一环断了,任务都不会跑,而且默认没有明显报错。
  3. 任务跑在 web 请求里,受 PHP-FPM 的 request_terminate_timeout、内存限制影响;set_time_limit(0) 也可能被 disable_functions 禁掉。
  4. 并发锁是 doing_cron 这个 option,默认 60 秒(WP_CRON_LOCK_TIMEOUT)。任务跑超过 60 秒,下一轮请求可能再起一个进程,出现重叠。

二、两种触发方式对照

维度

WP-Cron

系统 cron

触发者

访客请求

操作系统

精度

取决于流量

分钟级

是否依赖 loopback

是

否

长任务

受 FPM 超时/内存限制

CLI 无 web 超时

并发控制

doing_cron 锁 60 秒

可配合 flock

失败可见性

默认静默

可写日志、可看退出码

被外部请求触发

可以

不涉及

三、什么情况下必须换

按优先级:

1. 任务对时间敏感。 定时发布文章、会员到期降级、订阅续费、未支付订单自动取消、每日报表、邮件队列。晚几分钟可以,晚几小时就是事故。

2. 站点流量低,或者页面被整页缓存。 整页缓存命中时 PHP 不执行,init 不跑,WP-Cron 不触发。低流量站同理:没有访客就没有时钟。

3. 站点无法请求自己的域名。 常见于:DNS 还没切好、防火墙禁止出站、HTTPS 是自签证书、站点在容器内网、CDN 回源规则拦了 wp-cron.php。这时 spawn_cron() 的请求直接失败。

4. 有长任务。 备份、导入、图片批量处理、邮件队列。web 请求有超时,进程被 FPM 杀掉后任务停在半路,下次还可能重复。

5. wp-cron.php 被外部频繁请求。 任何人访问 /wp-cron.php 都会触发任务。锁能限制并发,但挡不住请求本身消耗 PHP-FPM 进程。

6. 多环境共用一个数据库。 staging 和 production 都会触发同一套 cron 事件,互相抢锁。需要按环境决定谁跑。

不适合换的情况也有:站点流量稳定、任务只有 wp_scheduled_delete 这类清理、没有时间敏感业务,继续用 WP-Cron 没问题,少一个系统依赖。

四、切换前先确认

先备份 wp-config.php,在 staging 上做一遍。

代码语言:bash
复制
wp cron event list --fields=hook,next_run_gmt,recurrence
wp cron test
wp config get DISABLE_WP_CRON
  • wp cron event list 看有哪些事件、下次运行时间。如果 next_run_gmt 已经过去很久,说明触发链有问题。
  • wp cron test 检查站点能否自己请求到 wp-cron.php。要在关闭 WP-Cron 之前跑。
  • wp config get DISABLE_WP_CRON 确认常量是否已经被定义。未定义会报错,属于正常。

再看一眼访问日志,确认现在是谁在触发:

代码语言:bash
复制
grep 'wp-cron.php' /var/log/nginx/access.log | tail -n 20

如果来源是大量不同的访客 IP,就是页面触发;如果只有固定几个 IP,可能已经有系统 cron 或监控在请求。

五、配置步骤

以 Ubuntu/Debian + Nginx + PHP-FPM 为例,其他环境替换路径。

1. 关闭页面触发

在 wp-config.php 里加一行,放在 /* That's all, stop editing! */ 之前:

代码语言:php
复制
define( 'DISABLE_WP_CRON', true );

这行只关闭「访客请求触发」,不关闭 wp-cron.php 本身。外部直接访问 /wp-cron.php 仍然会执行任务,所以后面还要限制 web 访问。

2. 选执行方式

方式 A:WP-CLI(推荐)

代码语言:bash
复制
/usr/local/bin/wp --path=/var/www/example.com/public cron event run --due-now

--due-now 只跑到期的事件。WP-CLI 在 CLI 下加载 WordPress,不受 web 超时限制,出错有输出。

方式 B:直接跑 wp-cron.php

代码语言:bash
复制
cd /var/www/example.com/public && /usr/bin/php wp-cron.php

少一个 WP-CLI 依赖,但 CLI 下没有 $_SERVER['HTTP_HOST'] 等变量,个别插件可能报错。能用 A 就用 A。

先确认命令路径:

代码语言:bash
复制
command -v wp
command -v php

3. 写进 crontab

用站点所属用户,不要用 root:

代码语言:bash
复制
sudo crontab -u www-data -e

写入:

代码语言:cron
复制
*/5 * * * * timeout 240 flock -n /tmp/wp-cron-example.lock /usr/local/bin/wp --path=/var/www/example.com/public cron event run --due-now --quiet >> /var/log/wp-cron-example.log 2>&1

几个点:

  • flock -n:上一轮没跑完时直接跳过,不叠加。
  • timeout 240:给这一轮一个上限,避免一个卡住的事件把锁一直占着。
  • --quiet:正常执行不输出;报错仍会进日志。
  • 绝对路径:cron 的 PATH 很短,wp、php 都写全路径。

日志文件先建好并给权限:

代码语言:bash
复制
sudo touch /var/log/wp-cron-example.log
sudo chown www-data:www-data /var/log/wp-cron-example.log

不想留日志就把重定向改成 >> /dev/null 2>&1,但排查时会少一个依据。

对时间特别敏感的任务,可以把 */5 改成 *(每分钟)。由于有 flock,不会叠加;代价是每分钟多一个进程。

4. 手动验证

代码语言:bash
复制
sudo -u www-data timeout 240 /usr/local/bin/wp --path=/var/www/example.com/public cron event run --due-now

没有报错,再用列表确认下一次运行时间:

代码语言:bash
复制
wp cron event list --fields=hook,next_run_gmt,recurrence

等一个周期,看日志有没有新内容,以及 next_run_gmt 是否正常往后走。

5. 限制 web 端 wp-cron.php

如果用 CLI 跑,web 端不需要被执行。Nginx 里只允许本机:

代码语言:nginx
复制
location = /wp-cron.php {
    allow 127.0.0.1;
    allow ::1;
    deny all;

    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass unix:/run/php/php-fpm.sock;
}

fastcgi_pass 的 socket 路径按 ls /run/php/ 的结果替换。

注意:如果站点在 CDN 后面,回源 IP 不是 127.0.0.1,上面的规则会把 CDN 也挡掉。这种情况要么放行回源 IP,要么不加这段,只依赖系统 cron 和 DISABLE_WP_CRON。

改完:

代码语言:bash
复制
sudo nginx -t && sudo systemctl reload nginx

6. 多站点

每个站点单独跑,指定 --url:

代码语言:cron
复制
*/5 * * * * timeout 240 flock -n /tmp/wp-cron-example.lock /usr/local/bin/wp --path=/var/www/example.com/public --url=https://example.com cron event run --due-now --quiet

多站点网络里,每个子站有自己的 cron 事件,需要分别触发。

六、常见坑

用 root 跑。 WP-CLI 会以 root 身份写 wp-content 下的文件,之后 web 用户改不动。用 crontab -u www-data 或 sudo -u www-data。

CLI 和 FPM 的 php.ini 不是一份。 memory_limit、disable_functions、扩展都可能不同。用 php -i | grep memory_limit 和 FPM 的配置对比。

--path 指错。 要指到 wp-config.php 所在目录,不是 wp-content。

时区。 cron 按服务器时区执行,WordPress 的定时事件按 UTC 存。跨时区团队先用 timedatectl 确认服务器时区,避免差几个小时。

锁卡住。 doing_cron 这个 option 如果残留,会挡住后续调度。先看:

代码语言:bash
复制
wp option get doing_cron

确认没有任务在跑,再删除:

代码语言:bash
复制
wp option delete doing_cron

不要在任务执行期间删。

插件自己的队列。 有些插件把队列挂在 WP-Cron 上,切换后要在插件设置里确认队列仍在跑。用 wp cron event list 能看到对应 hook。

CDN 缓存了 wp-cron.php**。** 如果 CDN 规则把 PHP 当静态资源缓存,要排除这个路径。

改了 DISABLE_WP_CRON 但没加系统 cron。 结果就是所有定时任务停摆。先加系统 cron,再关页面触发,顺序别反。

七、检查清单

  • wp cron test 通过(关闭前)
  • wp-config.php 里 DISABLE_WP_CRON 为 true
  • 系统 cron 以 web 用户运行
  • wp / php 使用绝对路径
  • 有 flock,长任务有 timeout
  • 日志文件存在且 web 用户可写
  • 手动跑一次 cron event run --due-now 无报错
  • 观察 24 小时,next_run_gmt 正常推进
  • web 端 wp-cron.php 已限制,或确认不需要限制
  • 插件队列、备份、邮件任务各自跑过一次

如果站点是交给别人部署的,把这一项写进交付清单:确认 DISABLE_WP_CRON 和系统 cron 都已配置,并留下日志位置。我们的代部署服务会把定时任务一起配好,交付时附一页说明:Setup。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、WP-Cron 的触发链路
  • 二、两种触发方式对照
  • 三、什么情况下必须换
  • 四、切换前先确认
  • 五、配置步骤
    • 1. 关闭页面触发
    • 2. 选执行方式
    • 3. 写进 crontab
    • 4. 手动验证
    • 5. 限制 web 端 wp-cron.php
    • 6. 多站点
  • 六、常见坑
  • 七、检查清单
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档