优先选 Redis;因其吞吐高、支持延迟/重试、可长驻运行,而 Database 易因表锁和轮询成瓶颈,且不原生支持延迟任务。

队列驱动选 redis 还是 database?
Laravel API 场景下,队列本质是为解耦耗时操作(比如发邮件、生成报表、调第三方接口),但选错驱动会直接卡住请求或丢任务。redis 吞吐高、支持延迟/重试、能用 php artisan queue:work --daemon 长驻,适合中高并发 API;database 简单,但 MySQL 表锁+轮询查表,QPS 上去后 jobs 表容易成瓶颈,且不支持原生延迟任务(得靠 available_at 字段 + 定时器模拟)。
- 生产环境别用
sync驱动——它根本没进队列,是同步执行,API 响应时间直接受任务拖累 - 如果已用
database且发现jobs表增长快、queue:work日志里频繁出现SQLSTATE[HY000]: General error: 1205 Deadlock found,说明该切redis -
redis需确认配置里REDIS_CLIENT是predis或phpredis,后者性能更好,但扩展必须已安装
dispatch() 调用后任务没进队列?检查这三处
常见现象:API 返回成功,但日志里没看到任务被消费,redis-cli keys "queues:*" 也查不到数据。
- 确认
.env中QUEUE_CONNECTION=redis(或对应驱动名),不是sync,也不是拼错成redid - 检查任务类是否实现了
ShouldQueue接口,且没在构造函数里传入不能序列化的对象(比如Request实例、DB连接) - Laravel 10+ 默认禁用闭包任务,如果用
dispatch(function () { ... }),需在config/queue.php中把allow_sync_dispatching设为true(不推荐,仅调试用)
API 请求里 dispatch 失败怎么捕获?别只 try-catch dispatch()
dispatch() 本身极少抛异常——它只是把任务塞进 Redis 或写进数据库,失败往往发生在后续消费阶段。
- 消费失败默认重试 3 次,然后进
failed_jobs表,需主动监听Illuminate\Queue\Events\JobFailed事件做告警 - 如果任务里调了外部 HTTP 接口,记得加
try/catch包住Http::timeout(10)->post(...),否则超时会直接让整个 job 失败,且不返回具体错误给 API 层 - 想在 API 响应里带任务 ID 供前端轮询状态?别直接返回
$job->id,要用dispatchNow()的返回值或自己生成 UUID 存到缓存里,因为dispatch()返回的是PendingDispatch对象,没 ID 字段
queue:work 进程挂了怎么办?别靠 supervisor 自动拉起就完事
API 流量波动大时,queue:work 进程可能因内存溢出、Redis 连接断开或 PHP Fatal Error 被 kill,supervisor 虽能重启,但中间几秒的任务会积压甚至丢失。
- 在
supervisord.conf里设startsecs=0和autorestart=true是基础,但必须加stopwaitsecs=30,否则 SIGTERM 来不及处理完当前 job 就被 SIGKILL 强杀 - 生产环境务必开
--max-jobs=1000和--max-time=3600,防止单个进程跑太久内存泄漏 - Redis 驱动下,如果
queue:work进程意外退出,未 ack 的任务会在retry_after时间后自动重回队列(默认 90 秒),但这个窗口期 API 用户看不到任何反馈——所以关键任务建议加「任务注册」步骤:先写一条task_status记录为pending,消费成功再改done
队列不是加个 dispatch() 就万事大吉,API 场景下最麻烦的是失败边界模糊:是网络抖动?Redis 挂了?还是任务逻辑里某个依赖没判空?得从驱动选型、异常捕获点、进程管理三个层面一起卡住。










