## 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. |
||
|---|---|---|
| .. | ||
| factories | ||
| migrations | ||
| seeders | ||
| .gitignore | ||