使用Octane::concurrently时模型观察者中Auth::user()为空的问题
问题原因
Octane的concurrently方法会把闭包放到独立的执行线程/进程里跑,这些异步任务不会自动继承当前请求的认证上下文。Laravel的Auth::user()依赖请求生命周期内的上下文绑定,异步闭包里没有这个上下文,所以返回null。
解决方案
方案1:直接传用户ID,跳过观察者里的Auth依赖
在主线程先拿到用户ID,创建模型时直接把created_by塞进$data里,不用在观察者里依赖Auth:
$userId = Auth::id(); [$contract, $contractType] = Octane::concurrently([ fn() => Contract::create(array_merge($data, ['created_by' => $userId]), $loadRelationships), fn() => collect(ContractTypeEnum::cases()) ->filter(fn($enum) => strtolower($enum->label()) === strtolower($data['contract_type'])) ->first() ->name, ]);
这种方式最简单直接,还能减少观察者对全局状态的依赖。
方案2:在异步闭包里手动绑定认证用户
如果一定要在观察者里用Auth::user(),可以在主线程先拿到用户实例,然后在闭包里手动设置给Auth:
$user = Auth::user(); [$contract, $contractType] = Octane::concurrently([ fn() => { Auth::setUser($user); return Contract::create($data, $loadRelationships); }, fn() => collect(ContractTypeEnum::cases()) ->filter(fn($enum) => strtolower($enum->label()) === strtolower($data['contract_type'])) ->first() ->name, ]);
注意:如果用的是Swoole这类Octane驱动,要确保User模型能被序列化(Laravel默认的User模型是支持的)。
方案3:给观察者加 fallback 逻辑
修改观察者的creating方法,优先用模型上已经设置的created_by,没有的话再尝试从Auth拿:
// 观察者代码 public function creating(ContractModel $contract) { if (empty($contract->created_by) && Auth::check()) { $contract->created_by = Auth::user()->id; } }
然后调用的时候和方案1一样,在主线程传created_by就行,这样不管是同步还是异步调用都能兼容。
注意点
- Octane异步任务的上下文是完全独立的,除了你显式传进去的变量,别指望能直接拿到主线程的请求、Session、Auth这些东西。
- 尽量少在异步闭包里依赖全局状态,能用参数传的就用参数传,代码更健壮。
内容的提问来源于stack exchange,提问作者Alberto Lima
相关产品推荐
相关产品推荐

