必须在推任务时显式传入业务ID(如$order->id),存为public属性,handle()中用Log::info()注入日志,并重写displayName()方法以便Horizon搜索。

队列任务里怎么拿到业务 ID(比如订单号)
队列任务执行时默认脱离原始请求上下文,$request、session、auth()->id() 全都不可用。想关联订单或用户编号,必须在推任务时显式传入,不能靠运行时“猜”或“查”。
常见错误是直接在 handle() 里调用 Auth::id() 或试图从日志里反查请求头——这些在队列进程里根本不存在。
- 正确做法:把业务 ID 作为构造参数传进任务类,存在属性里,并在
__construct()中标记为public $tries = 3;等可序列化字段 - 别用闭包任务(
dispatch(function () {})),它无法可靠序列化业务上下文 - 如果 ID 来自模型,传
$order->id而不是$order实例本身,避免序列化整个模型引发内存或兼容问题
Laravel 队列日志怎么带上订单号或用户 ID
默认的 log 驱动只记录任务类名和状态,不带业务维度。要让每条日志可追溯,得改写日志上下文,而不是依赖全局日志处理器。
最稳的方式是在任务的 handle() 开头手动打点,用 Log::info() 显式注入业务 ID:
Log::info('Order processed', [
'order_id' => $this->order_id,
'user_id' => $this->user_id,
'job' => get_class($this),
]);
- 别依赖
context配置自动加字段——队列任务没有 request context,Log::channel('stack')也不会自动继承 - 如果用了
monolog自定义 handler,确保 handler 的write()方法能读取到任务实例的属性,而不是只处理静态日志消息 - 注意日志等级:用
info或debug,别用warning或error冲突真实异常
失败任务重试时业务 ID 还在不在
只要业务 ID 是作为构造参数传入并赋值给 public 属性(如 public $order_id;),它就会被 Laravel 序列化进 Redis/DB,重试时完整还原——这是 Laravel 队列的核心保障机制。
但容易踩的坑是:把 ID 存在 protected/private 属性,或在 handle() 里动态计算(比如查数据库再赋值),重试时这些逻辑会重新执行,可能拿到过期数据甚至报错。
- 必须用 public 属性接收并保存业务 ID
- 避免在
handle()开头做“二次查询补全”,这会让重试行为不可控 - 如果确实需要关联模型数据,用
Order::find($this->order_id)而不是Order::findOrFail(),防止重试时因数据已被删而中断
用 Horizon 查日志时怎么快速过滤某个订单的任务
Horizon 默认按任务类、状态、时间排序,不索引业务字段。想搜 order_id=12345,得提前把业务 ID 写进任务的 $displayName 或日志消息体里。
推荐在任务类里覆盖 displayName() 方法,返回含业务 ID 的字符串:
public function displayName(): string
{
return 'ProcessOrder:'.$this->order_id;
}
- 这样在 Horizon UI 的 “Jobs” 列表里就能直接看到
ProcessOrder:12345,支持关键词搜索 - 别依赖 Horizon 的 tag 功能来标记订单号——tag 是手动打的,没法随任务自动绑定,维护成本高
- 如果用了 DB 驱动,可以在
jobs表的payload字段里 grep,但性能差;不如日志 + displayName 双保险
业务 ID 关联这事看着小,但一旦漏掉,排查线上延迟或失败任务时就得翻好几层日志、对时间戳、猜上下文——所有省事的捷径,最后都变成更长的弯路。











