Laravel多租户环境下SPBU数据删除同步队列任务报错ModelNotFoundException的问题
Laravel多租户环境下SPBU数据删除同步队列任务报错ModelNotFoundException的问题
看起来你的问题出在删除事件中传递了已被删除的模型实例到队列任务,导致队列执行时尝试重新加载这个已不存在的Spbu模型,从而抛出ModelNotFoundException。我来帮你分析原因并给出修复方案:
问题原因
在Laravel中,当你把模型实例传递给队列任务时,框架默认会序列化模型的主键信息。当队列任务实际执行时,会尝试从数据库中重新查询这个模型(确保数据一致性)。但在deleted事件场景下,原Spbu模型已经被从数据库中删除了,所以任务执行时查询不到模型,就抛出了这个异常。
另外,你在delete分支的代码还有一个潜在问题:TenantSpbu::find($id)->delete()如果对应的TenantSpbu不存在,find会返回null,调用delete()会直接抛出致命错误,这也可能是报错的诱因之一。
修复方案
核心思路是删除操作不要传递已删除的模型实例,改用模型ID来同步租户数据,同时优化删除逻辑的健壮性:
1. 修改Observer的deleted方法
不再传递整个Spbu模型,只传递模型ID:
public function deleted(Spbu $spbu): void { SyncSpbu::dispatch($spbu->id, 'delete'); }
(create和update方法可以保持传递模型实例,因为此时模型还存在于数据库中)
2. 调整队列任务的代码
修改任务的构造函数和处理逻辑,兼容接收模型实例或ID,并优化删除分支的代码:
class SyncSpbu implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable; protected $payload; protected $action; /** * Create a new job instance. * @param Spbu|int $payload 模型实例(create/update)或ID(delete) * @param string $action (create|update|delete) */ public function __construct($payload, string $action) { $this->payload = $payload; $this->action = $action; } /** * Execute the job. */ public function handle() { $tenants = Tenant::all(); foreach ($tenants as $tenant) { tenancy()->initialize($tenant); try { switch ($this->action) { case 'create': case 'update': // 确保获取到有效的Spbu模型 $spbu = $this->payload instanceof Spbu ? $this->payload : Spbu::findOrFail($this->payload); $tenantSpbu = TenantSpbu::updateOrCreate( ['id' => $spbu->id], [ 'nama' => $spbu->nama, 'alamat' => $spbu->alamat, 'latitude' => $spbu->latitude, 'longitude' => $spbu->longitude, ] ); break; case 'delete': // 直接用ID批量删除,即使不存在也不会报错 TenantSpbu::where('id', $this->payload)->delete(); break; } } catch (\Exception $e) { Log::error("Error syncing SPBU to tenant {$tenant->id}: " . $e->getMessage()); } tenancy()->end(); } } }
额外说明
- 为什么create/update可以保留模型实例?因为这两个事件触发时,
Spbu模型还存在于数据库中,队列任务执行时即使重新查询也能获取到数据,不会抛出异常。 - 优化后的删除逻辑
where('id', $id)->delete()避免了find返回null后调用delete()的致命错误,即使租户中没有对应的TenantSpbu记录,也能安全执行。
这样修改后,你的删除同步队列任务就不会再抛出ModelNotFoundException了,同时也提升了代码的健壮性。
备注:内容来源于stack exchange,提问作者Ardhan Novealdio
相关产品推荐
相关产品推荐

