dispatch()后任务没执行是因为Laravel队列默认不自动运行,需手动启动queue:work进程,且QUEUE_CONNECTION必须设为redis或database而非sync。

dispatch() 调用后任务没反应,不是代码写错了,而是 Laravel 5.5 的队列默认不自动运行——它只存任务,不执行任务。
QUEUE_CONNECTION 为什么不能是 sync
开发时 QUEUE_CONNECTION=sync 是默认值,它会让 dispatch() 立刻同步执行,看着像“成功了”,但完全违背异步初衷:请求线程仍被阻塞,无法实现后台处理。真要异步,必须切到 redis 或 database 驱动。
- 选
redis:需确认phpredis扩展已启用,且REDIS_HOST、REDIS_PORT在.env中配置正确 - 选
database:先跑php artisan queue:table+php artisan migrate,确保jobs表存在且可写 - 别漏掉
config/queue.php里对应驱动的retry_after值(Laravel 5.5 默认是 90 秒),超时未完成会被重发
queue:work 和 queue:listen 在 Laravel 5.5 怎么选
Laravel 5.5 还支持 queue:listen,但它会监听队列变化并每次 fork 新进程,开销大、不稳定;而 queue:work 复用同一进程,更轻量,是官方推荐方式。
-
php artisan queue:work:持续运行,适合生产,但要注意内存累积——Laravel 5.5 没有内置--max-jobs,得靠--memory=128或外部进程管理器控制 -
php artisan queue:listen:已标记为 legacy,仅作临时调试用,不要用于长期运行 - 终端关闭就停?必须用 Supervisor 守护,否则进程一断,任务就卡住
任务类 handle() 里直接用 $this->user 会出什么问题
在 Laravel 5.5 中,如果构造函数传入的是 Eloquent 模型实例(比如 new SendWelcomeEmail($user)),而任务类又没显式声明 use SerializesModels;,反序列化时很可能失败或拿到过期数据。
- 正确做法:构造函数只存 ID,如
$this->userId = $user->id;,然后在handle()里查库:$user = User::find($this->userId); - 错误写法:
$user = $this->user;(假设$this->user是模型对象)→ 序列化时可能含 Closure、Connection 等不可序列化内容,抛出Serialization of 'Closure' is not allowed - Laravel 5.5 的
SerializesModelstrait 会自动把模型转成 ID,但前提是模型没被修改过状态(比如调过save()),否则仍可能出错
Redis 驱动下任务重复执行怎么收场
Redis 不保证 exactly-once,网络抖动或 worker 崩溃未及时 ACK,任务就会被重新入队。Laravel 5.5 默认重试 3 次($tries = 3),但业务上仍可能发两封邮件、扣两次余额。
- 加幂等判断:比如发短信前先查
sms_logs表是否存在同order_id记录 - 手动控制唯一性:在任务类里定义
public $uniqueFor = 3600;(秒),配合自定义uniqueId()方法生成唯一键 - 别依赖数据库事务跨队列:
DB::transaction()在 dispatch 时已结束,handle() 是独立进程,事务不延续
真正难的不是写 dispatch,而是让 queue:work 在服务器上稳住不崩、任务数据不丢、重试边界可控——这些细节在 Laravel 5.5 里得手动补足,没后来版本那么省心。


















