How to retry after exception?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Retry logic is useful when failures are temporary, such as flaky network requests, rate limits, or transient database timeouts. It is not appropriate for every exception. A good retry mechanism retries only known transient failures, limits the number of attempts, and waits between attempts so it does not hammer the failing dependency.
Start With a Simple Retry Loop
A plain loop is often the clearest place to start.
Use it like this:
This is enough for straightforward scripts and small services.
Retry Only the Right Exceptions
Do not retry everything. Some exceptions represent permanent failures, such as invalid input, authentication errors, or programming bugs.
A retry loop should usually target a limited set of transient exceptions.
That keeps the retry policy honest. If you catch Exception broadly, you may hide real defects and waste time repeating requests that can never succeed.
Add Exponential Backoff
Using the same fixed delay every time can overload a struggling service. Exponential backoff increases the wait after each failure.
This is a much healthier default for remote systems than immediate rapid retries.
Add Jitter for Distributed Systems
If many clients fail at once, identical retry schedules can produce another spike of traffic all at the same moment. A small random jitter spreads those retries out.
This is especially important in services running many workers or many deployed instances.
Retrying a Real HTTP Call
This is the typical use case: an external dependency may fail briefly, but succeeding on a later attempt is realistic.
Know When Not to Retry
Retries are appropriate for transient failures. They are usually wrong for:
- malformed input
- permission errors
- '
404responses that reflect a missing permanent resource' - invariant violations and programming bugs
A retry policy should be tied to the failure mode, not added mechanically after every exception.
Common Pitfalls
The most common mistake is retrying all exceptions. That turns real bugs into delayed failures and makes diagnosis harder.
Another issue is retrying forever. Always cap the attempt count unless you are deliberately implementing a long-running worker with a different recovery strategy.
Developers also often forget backoff and hammer a failing service repeatedly. That can make the outage worse.
Finally, keep logging around retries. Without attempt counts and final failure logs, production retry behavior is hard to understand.
Summary
- Retry only failures that are likely to be temporary.
- Limit the number of attempts and preserve the final exception.
- Use exponential backoff, and add jitter when many clients may retry together.
- Do not retry programming errors or permanent business failures.
- Keep retry logic explicit so the recovery policy is easy to reason about.

