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:
+9
-4
@@ -29,9 +29,12 @@ type Settings struct {
|
||||
ClassifyOnImport bool `json:"classify_on_import"`
|
||||
}
|
||||
type Status struct {
|
||||
SyncError string `json:"sync_error"`
|
||||
IndexError string `json:"index_error"`
|
||||
LastSync string `json:"last_sync"`
|
||||
SyncError string `json:"sync_error"`
|
||||
IndexError string `json:"index_error"`
|
||||
LastSync string `json:"last_sync"`
|
||||
// SyncRetryAt is set only when every sync failure is a bank rate limit that
|
||||
// clears on its own; it is the earliest time an automatic retry is allowed.
|
||||
SyncRetryAt string `json:"sync_retry_at,omitempty"`
|
||||
BankingConfigured bool `json:"banking_configured"`
|
||||
AIConfigured bool `json:"ai_configured"`
|
||||
}
|
||||
@@ -49,6 +52,7 @@ type operational struct {
|
||||
Sessions []banking.Session `json:"sessions"`
|
||||
LastSync string `json:"last_sync"`
|
||||
SyncError string `json:"sync_error"`
|
||||
SyncRetryAt string `json:"sync_retry_at,omitempty"`
|
||||
Consents map[string]Consent `json:"consents"`
|
||||
AccountSync map[string]string `json:"account_sync"`
|
||||
BankingScope string `json:"banking_scope"`
|
||||
@@ -166,7 +170,8 @@ func (a *App) snapshot(ctx context.Context) (State, error) {
|
||||
a.indexError = ""
|
||||
}
|
||||
}
|
||||
return State{Data: d, Revision: rev, Settings: a.settings, Sessions: copySessions(a.ops.Sessions), CallbackURL: a.callbackURL, BankingAppID: a.bankingSettings.AppID, Connections: a.connections(d), Status: Status{SyncError: a.ops.SyncError, LastSync: a.ops.LastSync, IndexError: a.indexError, BankingConfigured: a.bank != nil, AIConfigured: a.classifier.APIKey != ""}}, nil
|
||||
status := Status{SyncError: a.ops.SyncError, SyncRetryAt: a.ops.SyncRetryAt, LastSync: a.ops.LastSync, IndexError: a.indexError, BankingConfigured: a.bank != nil, AIConfigured: a.classifier.APIKey != ""}
|
||||
return State{Data: d, Revision: rev, Settings: a.settings, Sessions: copySessions(a.ops.Sessions), CallbackURL: a.callbackURL, BankingAppID: a.bankingSettings.AppID, Connections: a.connections(d), Status: status}, nil
|
||||
}
|
||||
func (a *App) Snapshot(ctx context.Context) (State, error) {
|
||||
a.mu.Lock()
|
||||
|
||||
Reference in New Issue
Block a user