Laravel评论分数计算代码任务调度正常,放入队列作业报错原因
问题原因
核心原因是Laravel队列在序列化Eloquent模型时,不会保留withCount方法生成的临时动态属性。
你在调度任务中执行withCount('upVotes')、withCount('downVotes')得到的up_votes_count、down_votes_count是临时挂载在Comment模型实例上的属性,不属于模型的原生字段。当你把Comment模型传给Job后,Laravel会自动序列化模型仅保留主键信息,队列进程执行Job时会根据主键重新从数据库查询Comment实例,这时候原来预加载的count属性就丢失了,所以$item->up_votes_count为null,赋值给非空字段total_upvotes就触发了完整性约束错误。
修复方案
- 方案1:仅传递评论ID到Job,在Job内部查询时加载count属性
调度代码调整:
public function handle() { Comment::where('created_at', '>', Carbon::now()->subDays(3)) ->pluck('id') ->each(function ($id) { CalculateCommentScoreJob::dispatch($id); }); }
Job代码调整:
use Rank; protected $commentId; public function __construct(int $commentId) { $this->commentId = $commentId; } public function handle() { $item = Comment::withCount('upVotes') ->withCount('downVotes') ->findOrFail($this->commentId); $item->total_upvotes = $item->up_votes_count; $item->total_downvotes = $item->down_votes_count; $item->total_score = $this->score($item->up_votes_count, $item->down_votes_count); $item->fuzzed_score = (int)round($item->total_score + (rand(0,22) / 100 ) * $item->total_score, 0); $item->save(); }
- 方案2:把count值作为单独参数传递给Job,避免重复查询
调度代码调整:
public function handle() { $comments = Comment::where('created_at', '>', Carbon::now()->subDays(3)) ->withCount('upVotes') ->withCount('downVotes') ->get(); $comments->each(function ($item) { CalculateCommentScoreJob::dispatch($item->id, $item->up_votes_count, $item->down_votes_count); }); }
Job代码调整:
use Rank; protected $commentId; protected $upVotesCount; protected $downVotesCount; public function __construct(int $commentId, int $upVotesCount, int $downVotesCount) { $this->commentId = $commentId; $this->upVotesCount = $upVotesCount; $this->downVotesCount = $downVotesCount; } public function handle() { $item = Comment::findOrFail($this->commentId); $item->total_upvotes = $this->upVotesCount; $item->total_downvotes = $this->downVotesCount; $item->total_score = $this->score($this->upVotesCount, $this->downVotesCount); $item->fuzzed_score = (int)round($item->total_score + (rand(0,22) / 100 ) * $item->total_score, 0); $item->save(); }
内容的提问来源于stack exchange,提问作者Felix
相关产品推荐
相关产品推荐

