Routing is more than choosing an upstream. A production request also needs a timeout, a retry policy, an idempotency story, and an answer for what the user sees when the dependency is unavailable.
Make failure explicit
Every remote call can fail through a timeout, an application error, a connection problem, or an unexpected response. The caller should distinguish those cases where the product needs different recovery behavior. A retry that is safe for a read may duplicate a payment or create two jobs.
Keep retries bounded
Retries should have a small, explicit budget and use backoff with jitter. They should not multiply across several layers of a request. If a browser, API gateway, service, and queue consumer all retry the same operation, a small outage can become a traffic spike.
Design the fallback with the product team
A fallback can be a cached response, a queued operation, a read-only mode, or a clear error. The right choice depends on the workflow. A stale dashboard may be acceptable; silently accepting a transfer may not be.
Resilience is useful when it preserves a truthful system state. Observability, clear ownership, and recoverable operations matter as much as routing rules.