Laravel队列卡在pending状态主因是未启用真实驱动(如Redis)且配置未生效;需改QUEUE_CONNECTION、清缓存、用queue:work配合Supervisor常驻运行,并避免序列化大对象或连接未复用。

为什么 Laravel 队列卡在 pending 状态不执行?
绝大多数情况不是代码写错了,而是队列驱动没真正跑起来。Laravel 默认用 sync 驱动,它根本不会进队列,直接同步执行——这会让你误以为“队列在工作”,实际只是假象。
必须显式切换到真实驱动,比如 redis,并在 .env 中确认:
QUEUE_CONNECTION=redis REDIS_HOST=127.0.0.1 REDIS_PORT=6379
别漏掉 php artisan config:clear,Laravel 会缓存配置,改了 .env 不清缓存等于白改。
常见错误现象:
- 执行
dispatch(new SendEmailJob())后,php artisan queue:work没任何输出,数据库jobs表为空(说明根本没走数据库驱动) - Redis 里有
queues:default列表,但queue:work进程启动后立刻退出或无响应(多半是 Redis 连接失败或权限问题)
用 Supervisor 管理 queue:work 进程的最小可行配置
Supervisor 不是可选工具,是生产环境必须项。手动敲 php artisan queue:work 一旦终端断开或报错就停,任务直接积压。
关键点不在“怎么写配置”,而在“怎么验证它真在跑”:
-
command必须带--sleep=3和--max-jobs=1000,防止内存泄漏和无限重试拖垮进程 -
autostart=true和autorestart=true是基础,但必须加startsecs=5,否则 Supervisor 可能误判进程启动失败 - 日志路径建议用绝对路径,比如
/var/log/supervisor/laravel-queue.log,避免权限或路径解析问题
一个精简但可用的 /etc/supervisor/conf.d/laravel-queue.conf:
[program:laravel-queue] process_name=%(program_name)s_%(process_num)02d command=php /var/www/myapp/artisan queue:work redis --sleep=3 --max-jobs=1000 --max-time=3600 autostart=true autorestart=true startsecs=5 user=www-data numprocs=2 redirect_stderr=true stdout_logfile=/var/log/supervisor/laravel-queue.log
配完别忘了:supervisorctl reread && supervisorctl update && supervisorctl start laravel-queue:*
queue:work 和 queue:listen 到底该用哪个?
答案很明确:只用 queue:work,彻底忘掉 queue:listen。
queue:listen 是 Laravel 5.2 之前的遗留命令,它靠轮询 + include 重新加载代码,每次任务都重新启动整个 Laravel 应用上下文,内存占用高、启动慢、热更新不可靠,官方早已弃用。
queue:work 是常驻进程,复用应用实例,性能好得多,但代价是——代码变更后必须重启进程才能生效。这就是为什么 Supervisor 的 autorestart 要配合部署脚本使用:
- 部署新代码后,运行
supervisorctl restart laravel-queue:* - 或者用
php artisan queue:restart触发优雅重启(它只是往 Redis 写个信号,queue:work进程自己监听并退出)
别指望修改了 Job 类就自动生效,不重启进程,旧代码一直跑着。
Redis 队列延迟高?先检查这三件事
不是 Redis 不行,而是 Laravel 默认配置太“保守”。延迟高往往卡在连接池或序列化环节:
-
redis连接配置里没开pconnect(持久连接),每次取任务都新建 TCP 连接,耗时翻倍。在config/database.php的redis部分加'options' => ['prefix' => 'laravel_database_']不够,要确认 Redis 扩展支持phpredis并启用pconnect - Job 类用了大对象(比如整个
Request实例)作为构造参数,序列化成 JSON 后体积暴涨,Redis 读写变慢。应只传 ID 或必要字段,用__construct($userId)而非__construct(Request $request) - 没设置
--max-time=3600,单个任务超时后被强制 kill,Supervisor 立刻拉起新进程,反复 fork 导致系统负载飙升,间接拖慢其他任务
验证是否真卡 Redis:在 queue:work 命令后加 --verbose,看每条日志的时间戳间隔。如果“popping”和“processing”之间差几百毫秒,基本就是连接或序列化问题。









