diff --git a/app/Jobs/SyncBankingConnectionJob.php b/app/Jobs/SyncBankingConnectionJob.php index c22566ec..e66cef6a 100644 --- a/app/Jobs/SyncBankingConnectionJob.php +++ b/app/Jobs/SyncBankingConnectionJob.php @@ -80,6 +80,10 @@ class SyncBankingConnectionJob implements ShouldBeUnique, ShouldQueue 'error' => $e->getMessage(), ]); + if ($this->isRateLimitError($e)) { + return; + } + $connection->update([ 'status' => BankingConnectionStatus::Error, 'error_message' => $this->friendlyErrorMessage($e), @@ -203,6 +207,11 @@ class SyncBankingConnectionJob implements ShouldBeUnique, ShouldQueue return __('An unexpected error occurred during sync. Please try again later.'); } + private function isRateLimitError(\Throwable $e): bool + { + return $e instanceof RequestException && $e->response->status() === 429; + } + private function isAuthError(\Throwable $e): bool { return $e instanceof RequestException diff --git a/tests/Feature/OpenBanking/SyncBankingConnectionJobTest.php b/tests/Feature/OpenBanking/SyncBankingConnectionJobTest.php index 2013a5c6..44386f35 100644 --- a/tests/Feature/OpenBanking/SyncBankingConnectionJobTest.php +++ b/tests/Feature/OpenBanking/SyncBankingConnectionJobTest.php @@ -828,3 +828,34 @@ test('sends auth failed email for binance 403 error on final attempt', function && $mail->bankingConnection->id === $connection->id; }); }); + +test('rate limit error does not set connection status to error', function () { + $user = User::factory()->onboarded()->create(); + $connection = BankingConnection::factory()->create([ + 'user_id' => $user->id, + 'last_synced_at' => now()->subDay(), + ]); + Account::factory()->connected()->create([ + 'user_id' => $user->id, + 'banking_connection_id' => $connection->id, + 'external_account_id' => 'ext-123', + ]); + + $transactionSync = Mockery::mock(TransactionSyncService::class); + $transactionSync->shouldReceive('sync')->andThrow( + new \Illuminate\Http\Client\RequestException( + new \Illuminate\Http\Client\Response( + new \GuzzleHttp\Psr7\Response(429) + ) + ) + ); + + $balanceSync = Mockery::mock(BalanceSyncService::class); + + $job = new SyncBankingConnectionJob($connection); + $job->handle($transactionSync, $balanceSync); + + $connection->refresh(); + expect($connection->status)->toBe(BankingConnectionStatus::Active); + expect($connection->error_message)->toBeNull(); +});