queue_connection配置必须与实际驱动匹配,否则任务积压;queue:work需常驻运行并用supervisor等守护;dispatch后应查jobs表或redis队列确认入队,再检查进程是否存活及类路径是否正确。

QUEUE_CONNECTION 配置错,任务就永远卡在数据库里
队列不是“设了就能跑”,QUEUE_CONNECTION 必须和你实际部署的驱动匹配。常见错误是 .env 里写 QUEUE_CONNECTION=redis,但 Redis 没装、没启、或配置里的 REDIS_HOST 指向了错的地址——结果任务照常进表(比如 jobs 表),queue:work 进程却连不上,安静得像没这回事。
- 用 database 驱动?先跑
php artisan queue:table+php artisan migrate,否则表不存在,写入直接报错 - 用 redis 驱动?确认已装
predis/predis或启用phpredis扩展,且config/queue.php中connection值(如default)和config/database.php的 redis 键名一致 - 开发调试时可临时切回
QUEUE_CONNECTION=sync,任务会立即同步执行,方便验证逻辑是否正确,但别在生产环境留着
php artisan queue:work 不是“运行一次就完事”
queue:work 是一个常驻内存的消费者进程,不是脚本命令。它一旦退出(比如你关了终端、代码改了没重启、服务器重启),后续所有 dispatch 的任务都会积压,直到你手动再起一个。
- 本地开发:开个新终端窗口跑
php artisan queue:work,别关;改了 Job 类后必须 Ctrl+C 再重跑,否则缓存旧代码不生效 - 生产环境:必须用 Supervisor、systemd 或 pm2 等进程管理工具保活;只配
autorestart=true不够,还要加--tries=3 --sleep=3防止高频失败打爆日志 - 别用
queue:listen,它已废弃,性能差、不支持任务超时控制,Laravel 官方文档都标了 deprecated
dispatch() 后任务没执行?先查 jobs 表和日志
访问路由触发 SendWelcomeEmail::dispatch($user) 后没收到邮件,不代表代码错了,很可能是中间哪一环断了。
- database 驱动下,立刻查
jobs表:有记录说明分发成功;没记录说明dispatch()根本没走到,检查控制器里是否漏了use或调用方式(比如误写成new SendWelcomeEmail()而非dispatch(new ...)) - 有记录但一直不消费?看
queue:work终端输出有没有报错,比如Class 'App\Mail\WelcomeMail' not found—— 序列化对象反序列化失败,Job 类里引用的类路径不对 - Redis 驱动下,用
redis-cli连上去执行LLEN queues:default,看长度是否为 0;非零但没消费,大概率是queue:work进程挂了或连错了库
延迟任务 delay() 和失败重试,别只靠默认值
delay() 看似简单,但底层依赖的是驱动对“延时队列”的支持程度。database 驱动本质是轮询 available_at 字段,精度低、压力大;Redis 驱动用 ZADD + ZRANGEBYSCORE,才真正支持亚秒级延迟。
- 要用
delay(now()->addMinutes(5)),优先选 Redis;database 下可能偏差几十秒,高并发时还容易漏触发 - 失败任务默认重试一次就进
failed_jobs表,但你要先建表:php artisan queue:failed-table+php artisan migrate - Job 类里加
public function failed(\Throwable $exception) { \Log::error('SendWelcomeEmail failed', ['user' => $this->user, 'error' => $exception->getMessage()]); },比干等重试更早发现问题









