Yii 2: The Fast, Secure and Professional PHP Framework 定时任务调度:Cron 与 Queue 结合
在Web应用开发中,定时任务调度是后台处理的关键组成部分。无论是数据备份、邮件发送还是定期报表生成,都需要可靠的任务执行机制。Yii 2框架通过Cron(定时触发器)与Queue(任务队列)的结合,提供了高效、灵活的解决方案。本文将详细介绍如何在Yii 2中实现这一机制,解决任务堆积、执行超时和失败重试等常见问题。
控制台命令基础
Yii 2的定时任务调度基于控制台命令系统实现。控制台应用程序的入口脚本为yii,位于项目根目录,通过它可以执行各种后台任务。控制台命令继承自[[yii\console\Controller]]类,每个命令对应一个控制器,其中的动作方法即为具体的任务实现。
基本使用方法
运行控制台命令的基本语法如下:
yii <route> [--option1=value1 --option2=value2 ... argument1 argument2 ...]
例如,执行缓存清理命令:
yii cache/flush-all
查看所有可用命令列表:
yii
官方文档:docs/guide-zh-CN/tutorial-console.md
创建自定义定时任务
开发控制台控制器
创建自定义定时任务的第一步是开发控制台控制器。以下是一个示例,实现了一个简单的日志清理任务:
<?php
namespace app\commands;
use yii\console\Controller;
use yii\console\ExitCode;
use yii\helpers\FileHelper;
class LogController extends Controller
{
/**
* 清理过期日志文件
* @param int $days 保留天数
* @return int
*/
public function actionClean($days = 30)
{
$logPath = \Yii::getAlias('@runtime/logs/');
$expireTime = time() - $days * 86400;
foreach (FileHelper::findFiles($logPath, ['only' => ['*.log']]) as $file) {
if (filemtime($file) < $expireTime) {
unlink($file);
$this->stdout("Deleted expired log file: $file\n");
}
}
return ExitCode::OK;
}
}
命令选项与参数
通过重写[[yii\console\Controller::options()]]方法,可以为命令添加选项:
public function options($actionID)
{
return array_merge(parent::options($actionID), ['days']);
}
使用选项别名简化输入:
public function optionAliases()
{
return ['d' => 'days'];
}
现在可以通过以下命令执行带参数的清理任务:
yii log/clean -d=7
Cron:定时触发任务
Cron是Linux系统自带的定时任务调度工具,通过配置Cron表达式,可以定期触发Yii 2控制台命令。
基本Cron配置
编辑Cron表:
crontab -e
添加任务,例如每天凌晨2点执行日志清理:
0 2 * * * /path/to/yii log/clean -d=30 >> /var/log/yii-cron.log 2>&1
Yii 2中的Cron管理
虽然Yii 2核心未提供Cron管理模块,但可以通过社区扩展如yii2-cron实现更灵活的Cron任务管理。安装扩展后,可在配置文件中定义任务:
'components' => [
'cron' => [
'class' => 'mikehaertl\yii2\cron\Cron',
'jobs' => [
[
'command' => 'log/clean -d=30',
'schedule' => '0 2 * * *',
],
],
],
],
Queue:异步任务处理
对于耗时较长的任务(如邮件群发、大数据处理),直接通过Cron同步执行可能导致超时或阻塞。Yii 2的Queue组件提供了异步任务处理能力,支持多种驱动(如数据库、Redis、Beanstalkd)。
安装与配置Queue
在composer.json中添加依赖:
"require": {
"yiisoft/yii2-queue": "^2.0"
}
执行安装命令:
composer install
配置Queue组件(在config/console.php中):
'components' => [
'queue' => [
'class' => \yii\queue\db\Queue::class,
'db' => 'db',
'tableName' => '{{%queue}}',
'channel' => 'default',
'mutex' => \yii\mutex\MysqlMutex::class,
],
],
创建队列任务
生成任务类:
yii generate/queue-job SendEmail
编辑任务类(位于commands/jobs/SendEmailJob.php):
<?php
namespace app\commands\jobs;
use yii\base\BaseObject;
use yii\queue\JobInterface;
use yii\mail\MailerInterface;
class SendEmailJob extends BaseObject implements JobInterface
{
public $to;
public $subject;
public $body;
public function execute($queue)
{
\Yii::$app->mailer->compose()
->to($this->to)
->subject($this->subject)
->textBody($this->body)
->send();
}
}
将任务加入队列
在控制器或模型中:
Yii::$app->queue->push(new \app\commands\jobs\SendEmailJob([
'to' => 'user@example.com',
'subject' => 'Welcome',
'body' => 'Thank you for registering.',
]));
运行队列监听进程
启动队列监听进程,处理任务:
yii queue/listen
或使用queue/run命令一次性处理所有任务:
yii queue/run
Cron与Queue结合实现高级调度
架构设计
通过Cron定时触发控制台命令,将任务加入Queue,再由Queue Worker异步处理,形成完整的定时任务调度系统。
定时任务调度架构
实现步骤
- 创建任务分发命令:
class TaskController extends Controller
{
public function actionDispatch()
{
// 从数据库或配置中获取待执行任务
$tasks = Task::find()->where(['status' => Task::STATUS_PENDING])->all();
foreach ($tasks as $task) {
Yii::$app->queue->push(new ProcessTaskJob([
'taskId' => $task->id,
]));
$task->status = Task::STATUS_QUEUED;
$task->save();
}
return ExitCode::OK;
}
}
- 配置Cron定时触发分发命令:
*/5 * * * * /path/to/yii task/dispatch >> /var/log/yii-task.log 2>&1
- 启动Queue Worker:
yii queue/listen --verbose
监控与错误处理
日志记录
配置日志组件记录任务执行情况(在config/console.php中):
'log' => [
'targets' => [
[
'class' => 'yii\log\FileTarget',
'categories' => ['queue', 'cron'],
'logFile' => '@runtime/logs/queue-cron.log',
],
],
],
失败重试机制
Queue组件内置失败重试功能,配置重试次数和延迟:
'queue' => [
'class' => \yii\queue\db\Queue::class,
'ttr' => 300, // 任务执行超时时间(秒)
'attempts' => 3, // 最大重试次数
],
管理界面
通过yii2-queue-admin扩展可以实现任务管理界面,查看任务状态、重试失败任务等:
composer require --prefer-dist yiisoft/yii2-queue-admin
配置模块:
'modules' => [
'queue' => [
'class' => \yii\queue\admin\Module::class,
],
],
访问管理界面:http://your-app/queue
最佳实践与性能优化
任务拆分
将大型任务拆分为小型子任务,提高并行处理效率和失败恢复能力。
资源限制
在Cron任务中设置合理的资源限制,避免影响Web应用性能:
0 2 * * * /usr/bin/timeout 3600 /path/to/yii heavy/task >> /var/log/yii-cron.log 2>&1
使用进程管理工具
为确保Queue Worker持续运行,使用进程管理工具进行进程管理:
[program:yii-queue]
command=/path/to/yii queue/listen
directory=/path/to/app
user=www-data
autostart=true
autorestart=true
stderr_logfile=/var/log/yii-queue.err.log
stdout_logfile=/var/log/yii-queue.out.log
总结
Yii 2通过Cron与Queue的结合,提供了强大的定时任务调度能力。Cron负责定时触发,Queue处理异步任务,两者相辅相成,既保证了任务的及时执行,又避免了长时间任务对系统的影响。通过合理配置和优化,可以满足各种复杂场景下的任务调度需求。
官方文档:docs/guide-zh-CN/tutorial-console.md Queue组件源码:framework/queue/ Cron示例配置:config/console.php
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考




