laravel 的 schedule:run 不自动归档日志,因其仅触发调度、不处理日志轮转;输出由 crontab 直接接管,需借助 rotatelogs 或 logrotate 等系统工具实现日志归档。

为什么 schedule:run 的日志不自动归档?
Laravel 的 schedule:run 本身不处理日志轮转,它只是触发调度器判断哪些命令该执行;所有输出(包括 stdout/stderr)默认直接扔给 crontab,而 crontab 不管日志生命周期。如果你只写 > /dev/null 2>&1,那日志就彻底丢了;如果重定向到单个文件(如 > /var/log/laravel-schedule.log),这个文件会无限增长,最终撑爆磁盘。
用 rotatelogs 或 logrotate 做系统级轮转
最轻量、最可靠的做法是把日志交由系统工具管理,不依赖 PHP 框架逻辑。两种主流方式:
-
rotatelogs(Apache 工具,常驻进程式):适合需要按大小或时间切分、且希望实时写入的场景
示例 crontab 条目:* * * * * cd /var/www && /usr/bin/php artisan schedule:run 2>&1 | /usr/bin/rotatelogs -l -f /var/log/schedule-%Y%m%d.log 86400 -
logrotate(Linux 标准工具,定时扫描式):更通用,支持压缩、保留天数、postrotate 脚本
需配/etc/logrotate.d/laravel-schedule:/var/log/laravel-schedule.log {<br> daily<br> missingok<br> rotate 30<br> compress<br> delaycompress<br> notifempty<br> create 0644 www-data www-data<br> sharedscripts<br> postrotate<br> if [ -f /var/run/php/php-fpm.pid ]; then<br> kill -USR1 `cat /var/run/php/php-fpm.pid`<br> fi<br> endscript<br>}
在 Laravel 任务内部做应用级归档(如 post:archive)
当归档逻辑本身就是业务需求(比如把数据库旧文章移到归档表、压缩并上传到 S3),就不能只靠日志轮转——得让任务自己完成数据迁移+清理+标记。关键点:
- 归档任务必须幂等:重复执行不能导致数据错乱,建议加
WHERE archived_at IS NULL或用upsert防重 - 避免单次扫描全表:用
chunkById()分批处理,例如Post::where('created_at', 'subDays(90))->chunkById(500, function ($posts) { ... }) - 归档后务必更新原记录状态或删除,否则下次又捞出来,形成“伪归档”循环
- 如果归档目标是文件系统(如移动日志文件),注意 PHP 进程用户权限是否能读写目标路径
别忽略锁和并发冲突
日志轮转本身不会冲突,但归档任务如果被多个 worker 同时触发(比如误配了多条 crontab、或队列监听器重复启动),就可能造成数据重复迁移、文件覆盖、甚至 MySQL 死锁。必须加防重机制:
- 用
Cache::lock('archive:posts', 3600)包裹整个归档流程,超时自动释放 - 对关键表加数据库行锁(
select ... for update)仅在必要时,避免长事务阻塞 - 检查
schedule:run是否被多个服务器共用同一份 crontab(常见于集群环境),应只允许主节点执行调度
真正容易被忽略的是归档后的验证环节:没人看日志不代表成功,得有兜底手段——比如每天凌晨跑一个校验脚本,比对源表未归档数 + 归档表新增数 + 日志中记录的 processed count,三者不一致就得告警。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











