Laravel 10事件监听器tries与failed方法不生效问题排查
Laravel 10事件监听器
tries与failed方法未生效排查 问题描述
开发Laravel 10项目时,已配置事件UptimeHourlySummaryStatCreation和对应队列监听器StoreUptimeHourlySummaryStat。按Laravel队列机制,设置failed方法后,任务失败应执行该方法而非存入failed_jobs表;同时已将监听器的tries设为1,但数据库显示任务实际重试3次才失败,且failed方法未触发。
可能原因及解决办法
1. 队列连接retry_after配置引发超时重试
监听器使用的database-short-running连接将retry_after设为80秒。若任务执行时未主动释放锁,Laravel会判定任务超时,自动重试任务,此逻辑会绕过监听器的tries配置。
解决方式:
- 确保任务在
retry_after时长内完成;若任务逻辑无法缩短,可适当调大retry_after值,但需同步调整队列Worker的--timeout参数(默认60秒)。 - 若任务需长时间运行,在任务中主动调用
$this->release()释放锁,避免被判定为超时重试。
2. Worker全局重试配置覆盖监听器tries
启动队列Worker时若指定了--tries参数(如php artisan queue:work --tries=3),该全局配置会覆盖监听器类中定义的tries属性。
解决方式:
- 启动Worker时移除全局
--tries参数,让监听器的tries生效:php artisan queue:work database-short-running --queue=statistics-hourly - 或在Worker命令中指定与监听器一致的
tries值:php artisan queue:work database-short-running --queue=statistics-hourly --tries=1
3. failed方法未触发的额外排查点
- 确认
failed方法参数正确:第一个参数为事件实例,第二个为Throwable实例(当前代码参数无误),可在方法内添加日志写入逻辑,验证是否真的未执行。 - 若任务因超时被重试而非代码抛出异常,
failed方法不会触发,只有当任务达到最大尝试次数后才会执行该方法。
相关代码
事件代码(UptimeHourlySummaryStatCreation.php)
<?php namespace App\Events; use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PresenceChannel; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; class UptimeHourlySummaryStatCreation { use Dispatchable, InteractsWithSockets, SerializesModels; /** * Create a new event instance. */ public function __construct( public mixed $lastCheckedAt, public int $userId, public int $monitorId, public int $totalResponseDuration = 0, public int $totalChecksPerformed = 1, public int $totalSuccessfulChecksPerformed = 0, public int $totalFailedChecksPerformed = 0 ) {} /** * Get the channels the event should broadcast on. * * @return array<int, \Illuminate\Broadcasting\Channel> */ public function broadcastOn(): array { return [ new PrivateChannel('channel-name'), ]; } }
监听器代码(StoreUptimeHourlySummaryStat.php)
<?php namespace App\Listeners; use App\Events\UptimeHourlySummaryStatCreation; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; use App\Models\UptimeHourlySummaryStat; use Carbon\Carbon; use Throwable; class StoreUptimeHourlySummaryStat implements ShouldQueue { use InteractsWithQueue; /** * The name of the connection the job should be sent to. * * @var string|null */ public $connection = 'database-short-running'; /** * The name of the queue the job should be sent to. * * @var string|null */ public $queue = 'statistics-hourly'; /** * The number of times the queued listener may be attempted. * * @var int */ public $tries = 1; /** * Create the event listener. */ public function __construct() { // } /** * Handle the event. */ public function handle(UptimeHourlySummaryStatCreation $event): void { $statistic = UptimeHourlySummaryStat::firstOrCreate([ 'user_id' => $event->userId, 'monitor_id' => $event->monitorId, 'grouped_at' => Carbon::parse($event->lastCheckedAt)->format('Y-m-d H:00:00') ]); // set count of each check $statistic->total_checks_performed = $statistic->total_checks_performed + $event->totalChecksPerformed; $statistic->total_successful_checks_performed = $statistic->total_successful_checks_performed + $event->totalSuccessfulChecksPerformed; $statistic->total_failed_checks_performed = $statistic->total_failed_checks_performed + $event->totalFailedChecksPerformed; // set the response durations $statistic->total_response_duration = $statistic->total_response_duration + $event->totalResponseDuration; if (!$statistic->total_checks_performed) { $statistic->avg_response_duration = 0; } else { $statistic->avg_response_duration = round($statistic->total_response_duration / $statistic->total_checks_performed); } // set checked date and save $statistic->last_checked_at = Carbon::parse($event->lastCheckedAt); $statistic->save(); } /** * Handle a job failure. */ public function failed(UptimeHourlySummaryStatCreation $event, Throwable $exception): void { // ... } }
队列配置信息(queue.php)
// for short running queues 'database-short-running' => [ 'driver' => 'database', 'table' => 'jobs', 'queue' => 'short-running', 'retry_after' => 80, 'after_commit' => false, ], 'database' => [ 'driver' => 'database', 'table' => 'jobs', 'queue' => 'default', 'retry_after' => 90, 'after_commit' => false, ], // for long running queues 'database-long-running' => [ 'driver' => 'database', 'table' => 'jobs', 'queue' => 'long-running', 'retry_after' => 300, 'after_commit' => false, ],
内容的提问来源于Stack Exchange,提问作者Ryan H
相关产品推荐
相关产品推荐

