搜索全站
插件 11 分钟阅读

WP Crontrol 管理定时任务:查看、新增与排查 WP-Cron 事件

定时发布失败、备份不执行,多半是 WP-Cron 出了问题。本文用 WP Crontrol 查看与管理计划任务,讲清自定义周期写法、错过的任务如何补跑,以及 WP-CLI 排查命令。

U
UFO_PF 2023-04-06 · 阅读 11 分钟
WP 插件
阅读提示
本文约 4,005 字,预计阅读 11 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:「定时发布」变成「Missed schedule」,问题在调度层

WordPress 里有一类功能不依赖访客触发,而是按时间自动执行:定时发布文章、备份、插件扫描、邮件队列、缓存预热。它们都跑在 WP-Cron 之上——一个用数据库模拟的定时任务系统。

WP-Cron 有个天生弱点:它靠访问触发。有人访问站点时,WordPress 才去检查有没有到期该跑的任务;没人访问,任务就不会跑。低流量站点因此经常出现「定时发布没生效」,文章列表里挂着一条醒目的「Missed schedule」(错过计划)。反过来,高流量站点又可能因为并发触发,导致同一任务被重复排队。

要管理这套系统,最直观的办法是装 WP Crontrol。它能列出所有已登记的计划任务、显示下次执行时间与参数、支持手动执行与删除,还能添加自定义周期和 PHP 事件。配合 WP-CLI,基本可以覆盖所有排查场景。

原理分析:WP-Cron 的三个关键概念

概念 说明 常见问题
Hook(钩子名) 任务的唯一标识,如 wp_version_check 插件卸载后残留
Schedule(周期) hourly、twicedaily、daily 或自定义 自定义周期未注册导致任务变一次性
Args(参数) 传给钩子的参数,参与唯一性判定 参数不同视为不同任务

任务唯一性由「钩子名 + 参数」决定。这也是为什么 wp_next_scheduled() 在检查时要把参数一起传进去——参数不一致,wp_schedule_event() 就会再排一条重复任务,于是同一个动作被执行两次。

另一个常见问题是并发锁。WordPress 用 WP_CRON_LOCK_TIMEOUT(默认 60 秒)防止同一时刻多个进程同时跑 cron。任务执行超过这个时间或锁未正常释放,后续触发就会被跳过。此外 ALTERNATE_WP_CRON 常量用于某些不能发起 loopback 请求的环境(如内层有 HTTP 认证时),作为备用触发方式。

保姆级实操:从查看到治理

步骤1:安装并查看全部任务。 后台「工具 → Cron Events」会列出所有登记的任务,包含钩子名、参数、下次执行时间、周期。重点关注两类:下次执行时间停留在过去很久的(说明长期未触发)和钩子名明显属于已卸载插件的(残留任务)。

步骤2:用 WP-CLI 交叉核对。 命令行看到的是真实登记状态,便于批量处理。

# 列出所有计划任务
wp cron event list
# 查看某个特定钩子
wp cron event list --hook=wp_version_check --fields=hook,next_run,recurrence
# 测试 WP-Cron 是否正常
wp cron test

步骤3:手动补跑错过的任务。 发现某任务长期未执行,可以立即触发一次,观察是否报错。

# 立即运行所有到期任务
wp cron event run --due-now
# 只运行指定钩子
wp cron event run my_custom_hook

步骤4:注册自定义周期。 默认的 hourly、twicedaily、daily 往往不够用。用 cron_schedules 过滤器增加自定义周期,并在注册任务前检查是否已存在,避免重复排队。

<?php
// 注册自定义周期
add_filter( 'cron_schedules', function ( $schedules ) {
    $schedules['every_five_minutes'] = array(
        'interval' => 5 * MINUTE_IN_SECONDS,
        'display'  => '每 5 分钟',
    );
    return $schedules;
} );

// 注册任务:先检查,避免重复
add_action( 'init', function () {
    if ( ! wp_next_scheduled( 'mf_sync_inventory' ) ) {
        wp_schedule_event( time(), 'every_five_minutes', 'mf_sync_inventory' );
    }
} );

// 任务回调
add_action( 'mf_sync_inventory', function () {
    // 执行具体逻辑
    error_log( '[cron] 库存同步任务执行 ' . current_time( 'mysql' ) );
} );

步骤5:清理插件卸载后的残留任务。 卸载插件时若没有清理自己登记的任务,钩子会留在表里,每次触发都执行一次不存在的方法,产生 PHP 警告。

<?php
// 清理已失效的任务(把 hook 名换成实际的残留钩子)
add_action( 'init', function () {
    $timestamp = wp_next_scheduled( 'removed_plugin_hook' );
    if ( $timestamp ) {
        wp_unschedule_event( $timestamp, 'removed_plugin_hook' );
    }
    // 不确定参数时,用这个清除该钩子的所有登记
    wp_clear_scheduled_hook( 'removed_plugin_hook' );
} );

步骤6:修复 Missed schedule。 定时发布失败通常有两个原因:WP-Cron 没被触发,或者时区/时间设置不一致。先用 wp cron test 确认调度可用,再核对后台「设置 → 常规」的时区,最后用系统 Cron 兜底。

# 用系统计划任务兜底触发 WP-Cron(配合 wp-config.php 中的 DISABLE_WP_CRON)
*/5 * * * * /usr/bin/php /var/www/site/public_html/wp-cron.php?doing_wp_cron > /dev/null 2>&1

步骤7:把重活挪出高峰期。 备份、扫描、同步这类任务应避开业务高峰。用 WP Crontrol 修改任务的执行时间,或在系统 Cron 里限定执行窗口,与Wordfence 性能开销与优化设置里的思路一致。

步骤8:建立监控。 给关键任务加一条「最后执行时间」记录,超过预期间隔就告警。定时任务的可怕之处在于它失败得很安静。

<?php
// 记录任务最后执行时间,便于外部监控
add_action( 'mf_sync_inventory', function () {
    update_option( 'mf_sync_inventory_last_run', time(), false );
}, 1 );

常见踩坑

  1. 只加 DISABLE_WP_CRON 不配系统 Cron。所有定时任务全部停摆,包括定时发布。两者必须成对配置。
  2. 重复排队同一任务。注册时没有用 wp_next_scheduled() 检查,每次 init 都新增一条,最后同一动作执行几十次。
  3. 自定义周期注册晚于任务注册。任务登记时周期还不存在,会退化成一次性任务,跑完即消失。
  4. 参数不一致导致清理不掉。用 wp_clear_scheduled_hook() 时没传参数,只能清掉无参数的那条;带参数的任务要用 wp_unschedule_event() 指定参数。
  5. loopback 请求被阻断。站点加了 HTTP 认证或防火墙拦截了自身请求,WP-Cron 无法自触发,表现为任务永远不跑。可用 ALTERNATE_WP_CRON 或改用系统 Cron 解决。
  6. 案例:某站点后台长期出现 PHP Warning: call_user_func_array() expects parameter 1 to be a valid callback,一天几十条。用 WP Crontrol 一查,发现是半年前卸载的插件留下的钩子,每隔一小时触发一次不存在的函数。用 wp_clear_scheduled_hook() 清除后日志立刻干净。这类问题的通用排查法是:看警告里的函数名 → 在 Cron 事件列表里搜索同名钩子 → 确认插件已卸载后删除任务。
  7. 任务执行时间过长被并发锁跳过。备份或扫描跑得比 WP_CRON_LOCK_TIMEOUT 还久,后续触发被丢弃。
  8. 在低流量站点上依赖 WP-Cron。一天只有几十个访客的站点,定时任务的实际执行时间可能偏差很大。必须用系统 Cron 兜底。

总结

WP-Cron 的治理可以总结为一句话:看得见、补得跑、兜得住。看得见靠 WP Crontrol 与 wp cron event list;补得跑靠 wp cron event run --due-now;兜得住靠系统计划任务定期触发 wp-cron.php。日常维护里还要注意三件事:注册任务前先检查是否已存在、卸载插件后清理残留钩子、给关键任务加执行时间记录用于监控。做到这些,「定时发布失败」「备份没执行」这类问题基本不会再出现。数据库层面的冗余清理可配合Advanced Database Cleaner 清理冗余数据,插件更新的验证流程见WP Staging 插件建测试站点。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。