All topics
RxJSadvanced

Retry Strategies

Explain retry and retryWhen (or the modern retry with config) for automatically re-attempting a failed Observable.

Some failures are transient — a flaky network blip, a momentarily overloaded server returning a 503 — and automatically retrying the operation is often better UX than immediately surfacing an error to the user. RxJS's retry operator re-subscribes to the source Observable when it errors, effectively restarting the entire operation from scratch, up to a configurable number of attempts.

It's like redialing a phone number that gave a busy signal — retrying immediately and repeatedly is rude and unlikely to help, but waiting a bit longer each time you redial (exponential backoff) gives the other line a real chance to free up before you try again.

Key Concepts

1
The modern retry({ count, delay }) configuration object form (replacing the older, more manual retryWhen) lets you specify a fixed number of attempts and, critically, a delay — either a fixed number of milliseconds or a function computing a delay per attempt, which is how you implement exponential backoff (waiting progressively longer between each retry attempt) to avoid hammering an already-struggling server with immediate, rapid-fire retries.
retry({ count, delay })retryWhendelay
2
An important interview-level nuance is that a naive retry() with no configuration retries immediately and indefinitely on every single error, which is almost always the wrong default for production code — it can turn one failing request into a tight retry loop that makes an already-degraded backend worse, which is exactly why the count and delay options (or a custom retryWhen predicate in older code) exist and should essentially always be used deliberately rather than left at defaults.
retry()countdelayretryWhen
3
A thorough answer also distinguishes retry from catchError: retry re-attempts the exact same failed operation from scratch hoping for a different outcome, while catchError accepts the failure and substitutes something else entirely — the two are frequently combined, with a bounded retry attempting a few automatic recovery attempts first, and a catchError as the final fallback if all retries are exhausted and the operation is still failing.
retrycatchError