Skip to content

fix(fx): keep exchange rates warm and decouple the failure cooldown from the timeout - #220

Merged
zaxovaiko merged 3 commits into
devfrom
feat/BF-0/rates-hardening
Sep 24, 2026
Merged

zaxovaiko merged 3 commits into
devfrom
feat/BF-0/rates-hardening

Conversation

@zaxovaiko

Copy link
Copy Markdown
Member

Summary

Keeps configured exchange rates warm on a 30s schedule, gives the failure cooldown its own exchangeRate.failureCooldownMs knob (default 30s), and stops useExchangeRate(s) refetching inside the fresh window. BF-0

Why

  • Nothing refreshed rates on a schedule. Once a rate went hard-stale, the next caller fetched it synchronously, including callers holding a locked transaction (RG limit gate, rank accrual, social transfers), so they waited up to providerTimeoutMs on the vendor.
  • After a failed fetch the cooldown was exactly providerTimeoutMs, so during an outage almost every call waited out the timeout again.
  • The react hooks had no staleTime, so every mount and window refocus refetched a rate the server still considered fresh.

The warm-up reuses the existing getRate path and job-queue pattern (same shape as the wallet sweep cron): every wallet.cryptoCurrencies entry plus display currencies, minus the pivot, bounded at 4 concurrent fetches, per-currency failures logged and swallowed.

Alternatives considered

  • Longer hardMaxAgeMs only: hides the stall but serves older prices to limit checks.
  • Moving conversions out of locked transactions: larger refactor of each caller; warm rates remove the synchronous fetch in practice.

Risks

  • New config field with a default; no migration. Operators with a vendor rate limit see one fetch per currency per soft-stale window (~every 60-90s).
  • A rate missing from the warm list still falls back to the on-demand fetch.

…eout

Launch currencies now refresh on a ~30s schedule instead of relying on
demand-driven fetches, so a hot path holding a lock (RG limit gate, rank
accrual, a P2P transfer) never falls through to a synchronous vendor call.

A failed vendor call previously cooled down for exactly providerTimeoutMs,
so an outage added a full timeout stall to every call for its duration.
The cooldown is now its own failureCooldownMs config, defaulting well
above the timeout.

useExchangeRate/useExchangeRates now set staleTime: 60_000 and
refetchOnWindowFocus: false, matching the reader's own fresh window.
@zaxovaiko
zaxovaiko merged commit 38364b2 into dev Sep 24, 2026
2 checks passed
@zaxovaiko
zaxovaiko deleted the feat/BF-0/rates-hardening branch September 24, 2026 22:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant