Laravel任务偶发"No query results for model"报错及重试失效排查
问题分析与解决方案
一、子任务找不到Category模型的原因及解决
核心问题出在Laravel队列传递模型实例的机制上:
- 父任务
CalculateCategoryScores传递Category/Field实例给子任务时,Laravel不会序列化整个模型对象,只会序列化模型的主键和类名。子任务执行时,会重新通过主键查询数据库获取实例。 - 即便父任务构造时Category确实存在,到子任务执行阶段,仍可能出现以下情况导致查询失败:
- 数据库主从同步延迟:如果系统用了读写分离,父任务在主库读取数据,子任务从从库查询时,从库未完成同步(哪怕Category一年没修改,也可能存在临时同步异常)。
- 模型全局作用域干扰:检查Category模型是否有全局作用域(比如
where('active', 1)),子任务查询时会自动带上该作用域,若作用域逻辑存在漏洞,可能误过滤掉存在的记录。 - 模型实例状态异常:若父任务中的Category实例是通过非查询方式生成的(比如手动创建),序列化后子任务重新查询时会找不到对应数据。
解决办法:
- 避免直接传递模型实例,改为传递主键ID,在子任务中手动查询:
// 父任务分发时传递ID CalculateFieldScore::dispatch($category->id, $field->id); // 子任务接收ID并查询 public function __construct(int $categoryId, int $fieldId) { $this->categoryId = $categoryId; $this->fieldId = $fieldId; } public function handle() { $category = \Mz\Models\Ipa\Category::findOrFail($this->categoryId); $field = Field::findOrFail($this->fieldId); // 执行分数计算逻辑 } - 若使用读写分离,强制子任务从主库查询:
$category = \Mz\Models\Ipa\Category::on('mysql')->findOrFail($this->categoryId); - 检查Category模型的全局作用域,确保查询逻辑不会误过滤有效记录。
二、设置$tries = 3但任务仅执行一次就失败的原因
Laravel队列默认将ModelNotFoundException视为不可恢复异常,触发后直接标记任务失败,不会触发重试逻辑,哪怕你设置了$tries = 3。
解决办法:
- 手动捕获
ModelNotFoundException,主动触发重试:use Illuminate\Database\Eloquent\ModelNotFoundException; public function handle() { try { $category = \Mz\Models\Ipa\Category::findOrFail($this->categoryId); // 业务逻辑 } catch (ModelNotFoundException $e) { // 5秒后重试,可根据需求调整间隔 $this->release(5); } } - 定义
$retryUntil方法,指定任务的重试截止时间:public function retryUntil() { return now()->addMinutes(5); } - 检查Horizon配置文件
config/horizon.php,确保环境配置中未覆盖任务的重试次数设置。
内容的提问来源于stack exchange,提问作者naghal
相关产品推荐
相关产品推荐

