Back to News & Insights
JavaScript August 9, 2026 · 4 min read

Downstream started rate-limiting your Node BFF? Here's the retry layer that fixes it.

Outbound calls from a Node BFF need retry and rate limiting. Here is the failure pattern, the hand-rolled pitfall, and an alova/server middleware that does both.

Downstream started rate-limiting your Node BFF? Here's the retry layer that fixes it.

Your Node BFF proxies to a downstream API — a payment provider, a recommendations service, a partner's data feed. One Tuesday the partner starts returning 429 and the occasional 503. Suddenly your users see errors, and the partner's status page lists you as their top traffic source. Something has to change on your side.

It does the happy path. It does nothing for the bad one. A transient 503 from the partner becomes a hard error for your user. And nothing stops a misbehaving client from calling this endpoint in a loop — which means you loop against the partner, exactly when they're struggling.

Most of us reach for the obvious patch: a retry helper, and a manual counter for rate limiting.

This compiles. It also has three holes you only find in production: Retry storm. Ten concurrent requests each retry three times → thirty calls to a partner that's already down. You turned a blip into an outage. No jitter. Every client retries after the same one second, so they all fire together, a thundering herd on recovery. Per-process counters. That Map lives in one process. Behind a cluster or multiple instances, each worker counts on its own, so your "limit" is really limit × instances, and it resets wrong on restart.

You can fix all three by hand. People do, with varying success. The interesting part is that these are solved problems if the retry and the limit live with the request definition instead of bolted on after it.

alova isn't only a browser library. alova/server ships two server hooks — retry and createRateLimiter — that wrap a method and run when you send it. They use whatever alova instance you've set up, and on the server that instance uses the axios adapter just like on the client.

retry wraps the method. Defaults are three attempts, one second apart; you can grow the delay and add jitter so a fleet of BFF instances doesn't retry in lockstep.

First retry at ~1s, next at ~2s, next at ~4s, each with 10–30% random jitter. The downstream gets breathing room instead of a wall of retries.

createRateLimiter wraps a method and tracks usage by a key — an IP, a user id, a tenant. Hit the limit and it throws (it does not queue), so you return 429 and stop there.

keyPrefix namespaces the counter so it won't collide with other limiters. duration and points set the window — here, five requests per second per IP.

Combine the two around the outbound call. Rate-limit the inbound caller first; if they're under budget, make the outbound call with retry.

The retry only runs on the outbound partner call, so a rate-limited caller is rejected before any retry logic kicks in — you're not retrying your own 429s.

For multi-instance deployments, point the limiter at a shared store so the count is consistent across workers:

createRateLimiter is built on node-rate-limiter-flexible, so cluster, multi-thread, and redis-backed stores are all supported through the storage adapter.

Canonical source: alova server rate limiting — https://alova.js.org/tutorial/server/strategy/rate-limit

Related reading Server retry — https://alova.js.org/tutorial/server/strategy/retry Storage adapters (psc / redis) — https://alova.js.org/resource/storage-adapter/psc

alova is on GitHub (alovajs/alova) and npm (alova). Full docs at https://alova.js.org.

Want to discuss this further?

Book a free strategy call with our team to see how these insights apply to your specific business goals.

Book a consultation