直接用crontab调用Yii控制台命令最稳妥,因Web请求生命周期短、易超时且并发不安全;应编写分批删除、带休眠和日志的console命令,并配置绝对路径crontab定时执行。
直接用调用 Yii 控制台命令是最稳妥、最可控的方式,别碰或后台常驻 PHP 进程。
为什么不能在 Web 请求里做定时清理
Web 请求生命周期短、超时限制严(通常 30–60 秒),而数据清理常涉及大批量查询、事务、I/O,极易被中断或触发
错误;更危险的是,多个并发请求可能同时触发同一清理逻辑,导致重复删除、数据错乱或锁表。Yii 的
应用专为长时间、独占式任务设计,天然规避这些问题。
怎么写一个安全的清理命令(以清理过期订单为例)
在
下新建
:
}
用
参数控制保留窗口,方便测试和灰度
不直接
大范围扫描,先
拿主键,再分批删,降低锁粒度和事务体积
加
防止瞬间高负载冲击数据库
输出带颜色提示,便于日志识别状态
crontab 怎么配才不出错
运行
,添加这一行(路径必须绝对):
WOC-YII开源站群管理系统1.3
WOC-YII是rschome.com基于yii framework 1.1.8框架所开发的一款开源简易站群管理系统。它的功能与WOC完全一样。目前版本为V1.3,新版本正在开发中,同时欢迎大家参与到开发中来! WOC-YII 1.3在1.2的基础上优化了登录系统(密码加密),优化了权限控制系统,新增seo管理功能,新增自动安装向导! 程序框架:yiiframework1.1.8 配置文件:p
下载
必须写全路径,避免 cron 环境找不到 PHP
是项目根目录下的
文件,不是
或其他入口
是传递给命令的参数,等价于
把 stdout 和 stderr 合并追加到日志,方便排查失败原因(比如 DB 连接失败、权限不足)
别用
—— 它等价于
,但某些旧版 cron 解析不稳定,显式写
更可靠
磁盘空间没释放?先看是不是文件句柄还挂着
如果清理脚本本身也操作日志(比如用了
),删完后
发现空间没回来,跑这句检查:
若输出类似
,说明某个长进程(如 queue worker、debug watch)还在往已删文件写。此时:
重启对应进程(如
)
或改用
+
,避免删文件,只清空内容
不要依赖“删了就立刻释放”,这是 Linux 文件系统行为,不是 Yii 的问题
真正容易被忽略的点是:清理命令的事务隔离级别和数据库连接池配置。如果用的是 MySQL,默认
可能导致大查询期间 MVCC 版本堆积;建议在命令开头加
并手动控制提交节奏,而不是靠框架自动 commit。
crontabsleepmax_execution_timeconsoleconsole/controllersCleanupController.phpnamespace console\controllers;
use yii\console\Controller;
use yii\db\Query;
use yii\helpers\Console;
class CleanupController extends Controller
{
public function actionOrders($days = 90)
{
$cutoff = time() - ($days * 86400);
// 先查再删,避免大事务卡死
$ids = (new Query())
->select('id')
->from('order')
->where(['<', 'created_at', $cutoff])
->andWhere(['status' => 'cancelled'])
->column();
if (empty($ids)) {
$this->stdout("No expired cancelled orders found.\n", Console::FG_GREEN);
return self::EXIT_CODE_NORMAL;
}
// 分批删除,每批最多 1000 条
foreach (array_chunk($ids, 1000) as $batch) {
\Yii::$app->db->createCommand()
->delete('order', ['id' => $batch])
->execute();
usleep(10000); // 小休眠,减轻 DB 压力
}
$this->stdout("Deleted " . count($ids) . " orders.\n", Console::FG_YELLOW);
}$daysDELETE ... WHERESELECT idusleep()crontab -e0 2 * * * /usr/bin/php /var/www/myapp/yii cleanup/orders --days=180 >> /var/log/yii-cleanup.log 2>&1
/usr/bin/php/var/www/myapp/yiiyiiconsole.php--days=180$days = 180>> /var/log/yii-cleanup.log 2>&1@daily0 0 * * *0 2 * * *FileTargetdf -hlsof +L1 | grep 'runtime/logs'
php 12345 user 10w REG 8,1 1073741824 123456 /path/to/runtime/logs/app.error.log (deleted)supervisorctl restart my-queuelogrotatecopytruncateREPEATABLE READ\Yii::$app->db->beginTransaction();