Report a rate-limited bank sync as a wait, and name real failures

Two of three banks were only pacing us, yet the dashboard demanded attention,
printed four nested wrappers and a nanosecond UTC deadline, and the scheduler
retried hourly into a refusal whose end time the bank had already given.

A rate limit now carries its retry time as data: Status.SyncRetryAt is set when
every failure is self-clearing, the connection reports rate_limited with that
deadline, the dashboard says synchronization resumes by itself and renders the
time in the browser's zone, and the scheduler sleeps until the deadline instead
of spending hourly session checks. Sync now still tries immediately.

The third bank's "transaction retrieval failed" hid its cause. Provider
failures Finance Duck determines itself are typed as banking.ProviderError,
so an unreachable provider, a timeout or an unusable response, such as a booked
transaction without a booking date, is reported instead of the opaque fallback.
Provider response text still never reaches the message.
This commit is contained in:
Lars Nolden
2026-09-11 18:41:35 +02:00
parent dece0d5b79
commit b3e1c65a82
12 changed files with 305 additions and 52 deletions
+2
View File
@@ -146,6 +146,8 @@ Initial synchronization requests the selected number of **calendar months of boo
**HTTP 429 is a provider rate limit, not evidence that bank consent has expired.** Bank reads honor `Retry-After` and use bounded exponential retries. A longer or exhausted limit pauses further requests until the reported retry time; failed accounts keep their previous sync cursors and imported data. Session checks use the saved account metadata rather than fetching every account's details again. A failed session is reported once instead of also marking each of its accounts unavailable. After the cooldown, **Sync now** can retry; the warning clears after a successful sync. One-time authorization and code-exchange requests are never automatically replayed.
**A rate-limited sync is a wait, not a fault.** While every failing bank has supplied a retry time, the dashboard reports that synchronization retries by itself after that moment, the account card shows a rate-limit badge instead of a connection error, and the background scheduler sleeps until the deadline rather than retrying hourly into a refusal it already knows about. **Sync now** still tries immediately. Any failure without a supplied deadline keeps the hourly retry, and its cause is named where Finance Duck can determine it locally: an expired consent, an HTTP status, an unreachable provider, or a response it cannot use, such as a booked transaction without a booking date. Provider response text is never displayed.
Manual **Sync now**, **Import older history**, and balance requests forward the requesting user's IP, browser User-Agent, and available Accept headers to the bank as PSU metadata. Scheduled syncs never claim a user is present. This distinction matters: [Enable Banking documents background limits of roughly four fetches per day at many banks](https://enablebanking.com/docs/faq/#why-am-i-getting-429-response-code-are-there-rate-limits-for-the-api). A confirmed background `ASPSP_RATE_LIMIT_EXCEEDED` defers that account's affected endpoint for at least six hours, preserving longer provider hints; it does not block an eligible user-initiated fetch. General provider limits still apply to both. Bank requests are spaced by at least one second, with longer learned spacing after throttling.
### Import older history for a connected account