Yii框架需通过“控制台命令+系统crontab”组合实现定时清理任务,核心是创建继承yii\console\Controller的命令类(如app\commands\CleanController),定义actionOldLogs等方法,并在crontab中用绝对路径调用php yii clean/old-logs,配合flock锁、timeout超时、日志记录及规范退出码确保稳定执行。

Yii 框架本身不内置 Cron 调度器,所有定时清理类任务必须靠「控制台命令 + 系统 crontab」组合实现。想只改 PHP 代码就自动跑起来?不行——漏掉系统层配置,任务永远不会执行。
怎么写一个可被 crontab 调用的清理命令
核心是创建一个继承 yii\console\Controller 的类,放在 commands/ 目录下(如 app\commands\CleanController),并在其中定义带清理逻辑的 actionXXX 方法:
- 方法名必须以
action开头,比如actionOldLogs,对应命令行调用为php yii clean/old-logs - 不要在构造函数或初始化阶段做耗时操作,
init()中也尽量避免 DB 连接或文件扫描 - 若需访问数据库、缓存等组件,确保
config/console.php中已正确配置'db'、'cache'等组件 - 建议用
Yii::info()和Yii::error()记录关键节点,日志路径需在 console 配置中明确指定(如'log' => ['targets' => [['class' => 'yii\log\FileTarget', 'logFile' => '@app/runtime/logs/cron.log']]])
crontab 行怎么写才不踩坑
Linux 下添加到 crontab -e 的那一行,最容易出错的是路径和环境变量。直接复制网上的模板大概率失败:
-
/usr/bin/php必须写绝对路径,运行which php确认;容器或宝塔环境常是/www/server/php/81/bin/php这类非标路径 -
/path/to/yii必须是项目根目录下的可执行入口文件,不是yii.bat或yii.php,而是你部署时实际使用的那个(通常是/var/www/myapp/yii) - 别省略重定向:末尾加上
> /dev/null 2>&1,否则 cron 默认发邮件,没配 MTA 就会积压失败任务 - 测试时先手动执行一遍:
/usr/bin/php /path/to/yii clean/old-logs,确认无报错再加进 crontab
如何防止清理任务重复执行或卡死
清理类任务常因数据量大、锁表、超时而拖长执行时间,下次调度进来就会冲突:
- 在命令开头加文件锁:用
flock -n /tmp/clean_old_logs.lock -c "php yii clean/old-logs",避免并行 - 给 PHP 进程设超时:
timeout 300 /usr/bin/php ...(单位秒),防止 hang 死 - 在代码里主动检查上一次执行时间:查
runtime/logs/cron.log最后一行时间戳,或建一张task_lock表记录task_name和locked_at - 退出码要规范:成功返回
0,失败返回非0(如return 1;),crontab 才能识别异常
真正难的不是写那几行 PHP,而是让命令在凌晨两点稳定跑完、不抢资源、不丢数据、出错了还能快速定位——这些都得靠 crontab 行的严谨性和命令内部的防御性设计,缺一不可。


















