要实现并发执行(即即使上一次任务未完成,下一次任务也能按时启动),WordPress的内置定时任务无法满足需求。以下是几种可行的并发解决方案:
方案一:使用操作系统级Cron + HTTP请求(推荐)
原理:通过系统Cron直接触发HTTP请求,每次请求都是独立的PHP进程。
步骤:
- 创建触发端点(在主题的
functions.php或插件中):
// 注册REST API端点
add_action('rest_api_init', function() {
register_rest_route('concurrent/v1', '/run-a', [
'methods' => 'GET',
'callback' => 'a_function',
'permission_callback' => function() {
// 安全验证:检查密钥
return $_GET['key'] === 'YOUR_SECRET_KEY';
}
]);
});
// 需要并发的函数
function a_function() {
// 模拟耗时操作(超过10秒)
sleep(15);
error_log("[并发执行] 完成于: " . date('H:i:s'));
}
- 配置系统Cron(每10秒触发一次):
* * * * * curl "http://yoursite.com/wp-json/concurrent/v1/run-a?key=YOUR_SECRET_KEY"
* * * * * sleep 10; curl "http://yoursite.com/wp-json/concurrent/v1/run-a?key=YOUR_SECRET_KEY"
方案二:PHP多进程(pcntl扩展)
适用场景:命令行环境,需服务器支持pcntl扩展。
// 在独立PHP脚本中(例如:/path/to/concurrent.php)
function a_function() {
sleep(15);
file_put_contents('log.txt', '['.date('H:i:s').'] 完成'.PHP_EOL, FILE_APPEND);
}
// 主循环
while (true) {
$pid = pcntl_fork();
if ($pid == -1) {
die('无法创建子进程');
} elseif ($pid) {
// 父进程:等待10秒后继续
sleep(10);
} else {
// 子进程:执行任务
a_function();
exit; // 子进程结束
}
}
启动方式:
nohup php /path/to/concurrent.php > /dev/null &
方案三:消息队列(RabbitMQ + WP后台处理)
架构:
WordPress → 发布任务 → RabbitMQ → 后台Worker(并发消费)
- 安装依赖:
composer require php-amqplib/php-amqplib
- 发布任务(在WordPress中):
// 每10秒发布一次任务
function schedule_a_function() {
require_once('vendor/autoload.php');
$connection = new \PhpAmqpLib\Connection\AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('a_function_queue', false, true, false, false);
$msg = new \PhpAmqpLib\Message\AMQPMessage('run');
$channel->basic_publish($msg, '', 'a_function_queue');
$channel->close();
$connection->close();
}
// 通过WP-Cron或系统Cron调用 schedule_a_function
- Worker脚本(独立PHP进程):
// worker.php
require_once('vendor/autoload.php');
$connection = new \PhpAmqpLib\Connection\AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$callback = function ($msg) {
a_function(); // 执行实际任务
$msg->ack();
};
$channel->basic_qos(null, 5, null); // 并发5个进程
$channel->basic_consume('a_function_queue', '', false, false, false, false, $callback);
while (count($channel->callbacks)) {
$channel->wait();
}
启动多个Worker:
# 启动5个并发Worker
for i in {1..5}; do
nohup php worker.php > /dev/null &
done
方案对比
| 方案 | 并发能力 | 复杂度 | 可靠性 | 适用场景 |
|---|---|---|---|---|
| 系统Cron + HTTP | ★★★★ | ★★ | ★★★ | 通用场景,需服务器权限 |
| PHP多进程(pcntl) | ★★★★ | ★★★ | ★★ | 命令行环境,需pcntl扩展 |
| 消息队列(RabbitMQ) | ★★★★★ | ★★★★ | ★★★★★ | 高并发、分布式系统 |
| WordPress内置定时任务 | ★ | ★ | ★★ | 非并发场景(默认方案不支持) |
关键注意事项
- 资源控制:
- 设置最大并发数(如通过Cron的
sem或队列的prefetch_count) - 监控服务器负载(避免进程堆积)
- 错误处理:
// 示例:捕获异常并记录
try {
a_function();
} catch (Exception $e) {
error_log('任务失败: ' . $e->getMessage());
}
- 安全措施:
- HTTP端点必须验证密钥
- 消息队列使用VPN/私有网络
- 限制Cron任务的IP访问
对于大多数WordPress站点,方案一(系统Cron + HTTP端点) 是最佳平衡点,兼顾实现简单性和并发能力。若需企业级解决方案,推荐使用消息队列。

