whisper-money/app/Jobs
Víctor Falcón f800847591
feat(banking): back off scheduler when EnableBanking returns 429 (#352)
## Problem

Production logs show repeated EnableBanking 429s on the same
connections, every cron cycle:

```
[2026-05-04 18:00:55] EnableBanking API error status:429
  body: [HUB046] Allowed number of accesses exceeded for consent
[2026-05-04 21:47:12] EnableBanking API error status:429
  body: Daily PSU not present consultation limit has been exceeded
[2026-05-05 00:01:41] same connection, same error
[2026-05-05 06:01:41] same connection, same error
```

Root cause: `SyncBankingConnectionJob` returned early on 429s without
persisting any backoff state. The scheduler kept re-dispatching the same
connection on every run, hammering the provider and burning the daily
quota.

## Fix

Persist a per-connection backoff window so the scheduler stops
re-dispatching until the provider quota resets.

- New `rate_limited_until` column on `banking_connections`.
- On 429: derive the window from
  1. `Retry-After` header if present,
2. "Daily ..." message → next UTC midnight (matches PSU daily limit
semantics),
  3. default 1 hour (consent / generic).
- Job short-circuits with a `Skipped` sync log if the window is still
active.
- Successful sync clears the window.
- `SyncAllBankingConnectionsJob` + `SyncBankingConnections` command
filter out connections still inside their backoff.

## Tests

- Existing rate-limit test updated (now also asserts the backoff is
set).
- New: daily message → next UTC midnight.
- New: `Retry-After` header honoured (1800s).
- New: rate-limited connection skipped without calling provider.
- New: successful sync clears `rate_limited_until`.
- New: scheduler excludes connections whose backoff has not expired.

`php artisan test --compact
--filter="SyncBankingConnectionJobTest|SyncRetryAndLoggingTest|SyncBankingConnectionsCommandTest"`
→ 70 passed.
2026-05-05 09:39:32 +02:00
..
Drip Support soft-deleted users with reusable emails (#316) 2026-04-22 11:41:41 +01:00
AssignHistoricalTransactionsToBudget.php feat: Load transactions history on budget created (#72) 2026-01-22 11:10:15 +01:00
GenerateHistoricalLoanBalancesJob.php feat(loans): backfill historical balances on loan creation (#322) 2026-04-24 13:09:34 +01:00
GenerateHistoricalRealEstateBalancesJob.php feat(real-estate): auto-calculate revaluation % and generate historical balances (#253) 2026-04-15 12:18:33 +00:00
ReEvaluateTransactionRulesJob.php feat(transactions): re-add select all matching filters to bulk actions bar (#169) 2026-03-01 10:27:43 +00:00
SendDailyBankTransactionsSyncedEmailJob.php Support soft-deleted users with reusable emails (#316) 2026-04-22 11:41:41 +01:00
SendUpdateEmailJob.php Support soft-deleted users with reusable emails (#316) 2026-04-22 11:41:41 +01:00
SyncAllBankingConnectionsJob.php feat(banking): back off scheduler when EnableBanking returns 429 (#352) 2026-05-05 09:39:32 +02:00
SyncBankingConnectionJob.php feat(banking): back off scheduler when EnableBanking returns 429 (#352) 2026-05-05 09:39:32 +02:00
SyncBinanceHistoricalBalancesJob.php feat: Add Binance integration (#131) 2026-02-18 15:23:46 +01:00