Skip to content

fx-dashboard: a fallback that only fires on ERROR cannot rescue you from SLOW - #667

Merged
MikeyPetrillo merged 1 commit into
mainfrom
claude/sweet-brown-i99jl3
Aug 3, 2026
Merged

fx-dashboard: a fallback that only fires on ERROR cannot rescue you from SLOW#667
MikeyPetrillo merged 1 commit into
mainfrom
claude/sweet-brown-i99jl3

Conversation

@MikeyPetrillo

Copy link
Copy Markdown
Owner

Found while investigating a revenue question: prod's self-check was reporting fx-dashboard as a 504 outage — and the tool was fine. Its second publisher was sitting idle.

The defect

fx-dashboard has two sources: api.frankfurter.dev (primary) and open.er-api.com (keyless fallback). The fallback is wired to the primary's catch block.

That rescues a primary that fails. It does nothing for a primary that is merely slow — a slow call eventually succeeds, so the fallback never runs.

Measured 2026-08-03:

primary, warm ~0.06s
primary, cold 7.8s, then 11.6s
fallback ~0.08s, every time

Inheriting the default 15s timeout with a retry, a cold primary could hold a paid $0.015 call for up to 30s before failing over — and the 12s self-check gave up long before that and booked it as an outage.

The fix

The primary gets 2.5s and no retry. If the spec'd source cannot beat a host that answers in under a tenth of a second, it has already lost — and retrying it is worse than falling through, because the fallback is the retry.

The two publishers agree to 4dp on ECB daily reference rates, and the response already names which one served, so failing over costs the buyer nothing and is never silent.

Deliberately NOT blanket-applied

There are three frankfurter.dev call sites. fx-rate and fx-history have no fallback, so a short leash there would convert slow successes into fast failures and lower the hit rate on a paid call. Same upstream, opposite correct answer.

The test pins that difference, so a later "consistency" pass cannot quietly apply the leash to all three.

Verification

  • scripts/test-fx-failover.js — 12 assertions, offline, in CI
  • Mutations killed: reverting to the inherited default, stretching the budget past the self-check window, and applying the leash to a sole-source call
  • Sweeps clean: 295 lenient tools, 526/526 through MCP

Note on the test: its first locator matched the first mention of the hostname (the explanatory comment), and then the first call — which is fx-rate. It was asserting against the wrong one of three call sites while looking green on the mutation that mattered.

…ot rescue you from SLOW

Found while investigating a revenue question: prod's self-check was reporting
fx-dashboard as a 504 outage, and the tool was fine. Its second publisher was
sitting idle.

fx-dashboard has two sources - api.frankfurter.dev as primary, open.er-api.com
as a keyless fallback - and the fallback is wired to the primary's catch block.
That rescues a primary that FAILS. It does nothing for a primary that is merely
slow, because a slow call eventually succeeds and the fallback never runs.

Measured 2026-08-03: the primary answers in ~0.06s warm but took 7.8s and 11.6s
cold, while the fallback answered in ~0.08s every time. Inheriting the default
15s timeout with one retry, a cold primary could hold a PAID $0.015 call for up
to 30s before failing over, and the 12s self-check gave up long before that and
booked it as an outage.

The primary now gets 2.5s and no retry. If the spec'd source cannot beat a host
that answers in under a tenth of a second, it has already lost, and retrying it
is worse than falling through because the fallback IS the retry.

NOT blanket-applied, which is the part worth keeping. There are three
frankfurter call sites; fx-rate and fx-history have NO fallback, so a short
leash there would convert slow successes into fast failures and lower the hit
rate on a paid call. Same upstream, opposite correct answer, and the test pins
the difference so a later "consistency" pass cannot quietly apply it to all
three.

scripts/test-fx-failover.js (12 assertions, offline, in CI). Mutations killed:
reverting to the inherited default, stretching the budget past the self-check
window, and applying the leash to a sole-source call.

Note on the test: its first locator matched the first mention of the hostname,
which is the explanatory comment, and then the first CALL, which is fx-rate -
so it was asserting against the wrong one of three call sites while looking
green on the mutation that mattered.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@MikeyPetrillo
MikeyPetrillo merged commit 4b460f3 into main Aug 3, 2026
15 checks passed
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