Skip to main content
Back to the notebook

Engineering

Circuit breakers, graceful degradation, and UIs that stay calm

When TMDB goes down, Horrorometer doesn’t. The resilience patterns that keep an external-API-dependent product from melting.

Horrorometer depends on two external APIs — TMDB for film and TV data, Open Library for books. Both are reliable… most of the time. "Most of the time" is not an availability target you can build a product on.

The day TMDB had an extended outage, Horrorometer kept working. Here’s the stack of patterns that made that possible — in the order I’d recommend implementing them.

1. Timeouts, before anything clever

Every outbound call has a timeout, and it’s shorter than you’d think. A hanging request is worse than a failed one — it holds connections, ties up Workers CPU time, and makes the user wait for an error they could have had five seconds ago.

If the upstream doesn’t respond in time, fail fast and let the fallback layer handle it.

2. Retry with exponential backoff — and a cap

Three attempts, exponential backoff. But retries are a tax you pay to the upstream under stress, so cap them. Three is enough. And never retry non-idempotent calls with the same payload without thinking about what happens if the first attempt actually landed.

3. The circuit breaker: stop hammering a dead service

The core pattern. Horrorometer’s breaker works like this:

  • 5 failures within 60 seconds → the circuit opens
  • while open, calls fail immediately — no request leaves the building
  • after 30 seconds, one trial request goes through
  • 2 successes → the circuit closes and traffic resumes

That’s it. No external state, no monitoring dashboard required — a small state machine that answers one question: "should I even try?"

The value isn’t that it saves the user from errors. It’s that when TMDB comes back, Horrorometer recovers within 30 seconds instead of drowning it in a backlog of retries the moment it shows a pulse.

4. Graceful degradation: the UI never shows a hard error

The breaker decides whether to call the upstream. Degradation decides what the user sees when the answer is "no":

  • Cached data stays served — a slightly stale movie page beats an error page, every time.
  • Empty states are honest but calm: "We’re having trouble reaching our film data right now" — not a red banner, not a crash screen.
  • Writes queue where they can, and fail cleanly where they can’t, with a message that tells the user what to do next.

The user-facing rule: never show an error you can’t tell the user how to get past.

5. Fail-open, but only where it’s safe

Counter-intuitive one: Horrorometer’s rate limiting fails open. If the rate-limit store is unreachable, requests pass through, because a database outage should not lock every user out of the site. That’s the right trade for a review platform. It would be the wrong trade for an admin panel — the point is that it’s a deliberate decision, made per subsystem, not a default.

The payoffs you don’t expect

The obvious payoff is uptime. The unexpected one is what this does to your own head: once the failure paths are designed, an upstream outage stops being an emergency. Sentry fires, you glance at the graphs, you get on with your day. The resilience layer is what makes a solo-run product feel boring — and boring is the goal.

The full stack in one sentence: timeout, backoff, breaker, degrade — and make every failure a designed one.

Keep reading

More from the blog.

Accessibility

Accessible by default: how I bake it in from the first sketch

Accessibility isn’t a checklist at the end — it’s a posture. Here’s how I keep it present from wireframe through to production code.

6 min read
Product

Shipping solo: what I learned building three live products

Horrorometer, Kanaboards, and SENDadvisor all started as itches I wanted to scratch. Some patterns held across all three — and a few surprised me.

8 min read
UX

Designing for stressful systems: lessons from SENDadvisor

Families navigating SEND services are already overwhelmed. How do you design a directory that feels calm, trustworthy, and genuinely useful?

7 min read