Laravel 10事件处理器重复执行两次问题求助
Laravel 10事件监听器重复执行问题
我在Laravel 10中执行以下代码触发事件:
$reference = "ABCD1234"; event(new \App\Events\RewardOnBooking($reference));
触发后其他功能正常,但事件对应的handle函数会执行两次,数据库中出现重复的积分记录。
我的事件与监听器配置如下:
EventServiceProvider中的注册:
protected $listen = [ // 其他事件... 'App\Events\RewardOnBooking' => [ 'App\Listeners\AddCredit', ], ];
RewardOnBooking事件类:
public function __construct($reference) { $this->reference = $reference; }
AddCredit监听器类:
public function handle(RewardOnBooking $event): void { $userCredit = Credits::where('user_id', '=', Auth::user()->id)->orderBy('id', 'desc')->first(); if ($userCredit == null) { Credits::firstOrCreate( ['user_id' => Auth::user()->id], [ 'creditsAmounts' => 0, "description" => 'added credit for your first booking', ] )->first(); } else { $amount = rand(1, 5); Credits::create([ 'user_id' => Auth::user()->id, "creditsAmounts" => $userCredit['creditsAmounts'] + $amount, "description" => 'Added credit for your booking reference - ' . $event->reference, 'responce' => $amount, ]); } }
需求:确保事件触发时,监听器的handle方法只执行一次,避免重复添加积分。
排查与解决方案
1. 检查事件是否被重复触发
在触发事件的代码前后添加日志,确认代码是否被执行两次:
Log::info('准备触发RewardOnBooking事件,reference: '.$reference); event(new \App\Events\RewardOnBooking($reference)); Log::info('RewardOnBooking事件触发完成');
查看storage/logs/laravel.log,如果两条日志出现两次,说明触发逻辑被重复调用。
2. 检查监听器是否重复注册
- 查看
EventServiceProvider的boot方法,是否存在手动注册监听器的代码:
// 此类代码会导致重复注册 Event::listen(RewardOnBooking::class, AddCredit::class);
- 排查其他服务提供者,确认是否有重复绑定该事件监听的逻辑。
3. 队列配置检查(若使用队列)
如果事件实现了ShouldQueue接口:
- 清空队列重试列表,避免重复任务执行:
php artisan queue:flush
- 检查
.env中的QUEUE_CONNECTION,若为非sync驱动,确认是否有重复的队列进程在运行。
4. 路由/中间件重复触发检查
- 确认触发事件的路由是否被定义多次,或存在中间件导致请求被重复处理(比如调试中间件、异常重定向逻辑)。
5. 幂等性优化(兜底方案)
若以上排查无问题,可在监听器中添加幂等校验,确保同一订单只处理一次:
public function handle(RewardOnBooking $event): void { // 校验该订单是否已处理过积分 $processed = Credits::where('user_id', Auth::user()->id) ->where('description', 'like', '%'.$event->reference.'%') ->exists(); if ($processed) { return; } $userCredit = Credits::where('user_id', '=', Auth::user()->id)->orderBy('id', 'desc')->first(); if ($userCredit == null) { Credits::firstOrCreate( ['user_id' => Auth::user()->id], [ 'creditsAmounts' => 0, "description" => 'added credit for your first booking', ] ); } else { $amount = rand(1, 5); Credits::create([ 'user_id' => Auth::user()->id, "creditsAmounts" => $userCredit['creditsAmounts'] + $amount, "description" => 'Added credit for your booking reference - ' . $event->reference, 'responce' => $amount, ]); } }
建议:最好在
Credits表新增reference字段存储订单编号,通过精确匹配替代模糊查询,提升校验可靠性。
内容的提问来源于stack exchange,提问作者Aimless
相关产品推荐
相关产品推荐

