定时任务管“什么时候跑”,队列管“怎么稳稳地跑完”;TP6需用crontab触发think命令实现定时,用Redis+think-queue实现异步、重试与并发控制,二者组合可兼顾准时性与可靠性。

定时任务和队列任务在 ThinkPHP6 中解决的是两类不同问题:一个管“什么时候跑”,一个管“怎么稳稳地跑完”。混淆它们,容易导致任务漏执行、卡死、重复或超时失败。
定时任务:只负责准时唤醒,不承担业务重担
ThinkPHP6 本身没有常驻内存调度器,不能靠 HTTP 请求或内置 timer 长期可靠运行任务。真正可用的定时方案,是靠 Linux crontab 每隔固定时间点,调用一次 php think xxx:command 命令。
- 它本质是一次性脚本调用,执行完就退出,不维持进程
- 适合轻量、确定性高、耗时短的操作,比如:清理临时文件、检查服务状态、触发同步动作
- 如果命令里直接写导出 Excel、批量发短信、调第三方接口等耗时操作,很容易超时、阻塞后续 cron 调度,甚至被系统 kill
- 必须用绝对路径(
/usr/bin/php)、cd切到项目根目录、显式指定环境(如APP_ENV=production),否则 crontab 环境下大概率静默失败
队列任务:专为异步、可靠、可重试而设计
队列不是定时器的替代品,而是它的“执行搭档”。当你需要把一个动作**延后、异步、分步、带重试地完成**,就要交给队列。
- 典型场景:用户下单后发通知、生成报表、处理上传文件、调用慢速 API —— 这些都不该卡住 Web 响应,也不该挤在 cron 进程里硬扛
- 推荐使用
topthink/think-queue+ Redis:Redis 保证原子性与高性能,think-queue提供统一的任务类封装、失败重试(默认 3 次)、失败日志落库、并发控制 - 消费者用
php think queue:listen --daemon启动,配合supervisor守护,持续监听并消费消息 - 任务类必须继承
Job,在fire()方法中写业务逻辑;框架自动处理异常捕获、重试、延迟投递等
两者组合才是生产级做法
大多数真实需求,需要定时任务“发起”,再由队列“落地”:
立即学习“PHP免费学习笔记(深入)”;
- 例如每天凌晨 2 点同步订单:crontab 在 2:00 触发
php think sync:order,该命令只做一件事——把“同步今天全部订单”这个任务推入 Redis 队列 - 真正的拉取、解析、写库、发通知等耗时操作,由后台常驻的 queue 消费者一条条处理,失败可重试,不影响下次定时触发
- 这样既保证了“准时启动”,又保障了“执行可靠”,还避免了单次执行时间过长带来的各种风险
一句话判断该用哪个
问自己:这个动作是否必须在某个精确时间点开始? 如果是,用定时任务;这个动作是否可能失败、耗时、不该阻塞当前流程? 如果是,放进队列。两个答案都“是”,那就先定时触发,再投递队列。



















