Unravel › Java concepts › Cloud and operations
Retry and circuit breaker
Remote calls fail for short moments.
Learn these first
At a glance
If a shop door is stuck you try the handle again once or twice (retry).
- 1Retry: @Retryable(maxAttempts = 3, backoff = @Backoff(delay = 500, multiplier = 2)) repeats the call after 0.5 s, then 1 s, before the exception reaches the caller@Recover supplies a fallback after the last attempt.
- 2Circuit breaker: it counts recent failuresClosed means calls go through; when the failure rate passes a threshold it opens and calls fail immediately; after a wait it goes half-open, lets a few calls through and closes again if they succeed.
- 3Resilience4j offers @Retry, @CircuitBreaker, @RateLimiter, @Bulkhead and @TimeLimiter, usually with a fallbackMethod for what to return while the breaker is open
- 4Both are applied through proxies, so they only work on calls from another bean
- Only retry operations that are safe to repeat (idempotent): reading data, or writing with an idempotency key
- Retries multiply load: three attempts from each of 100 callers means 300 calls against a service that is already struggling
- The annotations are handled by an aspect that wraps the invocation in a retry loop or a state machine
@Retryable(retryFor = ResourceAccessException.class, maxAttempts = 3, backoff = @Backoff(delay = 500, multiplier = 2))public Quote fetchQuote(String symbol) { return restClient.get().uri("/quotes/{s}", symbol).retrieve().body(Quote.class);}@Recoverpublic Quote fallback(ResourceAccessException e, String symbol) { return Quote.unavailable(symbol);}- line 1 uses Retryable, the core of Retry and circuit breaker
- line 2 uses Backoff, the core of Retry and circuit breaker
- line 7 uses Recover, the core of Retry and circuit breaker
Read the full explanation (about 2 min)
Remote calls fail for short moments. Retry tries again after a pause; a circuit breaker stops calling a dependency that keeps failing, so a sick service is not hammered and your own threads are not all stuck waiting for it.
A mental model
If a shop door is stuck you try the handle again once or twice (retry). If it is clearly locked, you stop trying for a while and check back later (circuit breaker), instead of standing there rattling it.
How it works
Retry: @Retryable(maxAttempts = 3, backoff = @Backoff(delay = 500, multiplier = 2)) repeats the call after 0.5 s, then 1 s, before the exception reaches the caller. @Recover supplies a fallback after the last attempt.
Circuit breaker: it counts recent failures. Closed means calls go through; when the failure rate passes a threshold it opens and calls fail immediately; after a wait it goes half-open, lets a few calls through and closes again if they succeed.
Resilience4j offers @Retry, @CircuitBreaker, @RateLimiter, @Bulkhead and @TimeLimiter, usually with a fallbackMethod for what to return while the breaker is open.
Both are applied through proxies, so they only work on calls from another bean.
Going deeper
Only retry operations that are safe to repeat (idempotent): reading data, or writing with an idempotency key. Retrying "charge the card" can charge twice.
Retries multiply load: three attempts from each of 100 callers means 300 calls against a service that is already struggling. Use exponential backoff with random jitter, and a small attempt limit.
Always combine retries with timeouts. A retry around a call that can hang forever just hangs three times as long.
A fallback that silently returns an empty or default value hides the outage. Log it, count it in a metric and decide whether the caller should see an error instead.
Under the hood
The annotations are handled by an aspect that wraps the invocation in a retry loop or a state machine. The circuit breaker keeps a sliding window (by count or by time) of outcomes in memory per named breaker, so each instance of your application has its own state.
Common mistakes
- Retrying non-idempotent operations.
- No backoff or jitter, so retries arrive in a synchronized wave.
- Retrying calls that have no timeout.
- A fallback that hides failures completely.
- Calling the annotated method from within the same class.
How Unravel recognises it
When you paste code, Unravel looks for these signs of retry and circuit breaker. Spotting them yourself is a good habit when you read unfamiliar code:
- Annotations:
@Retryable@Recover@EnableRetry@CircuitBreaker@Retry@RateLimiter@Bulkhead@TimeLimiter@Backoff - Types:
RetryTemplateCircuitBreakerRegistryRetryConfigCircuitBreakerConfig
Part of a learning path
- Reliable code · previous: Logging with SLF4J · next: JUnit tests
Related concepts
Frequently asked questions
What is Retry and circuit breaker?
Remote calls fail for short moments. Retry tries again after a pause; a circuit breaker stops calling a dependency that keeps failing, so a sick service is not hammered and your own threads are not all stuck waiting for it.
What are the most common mistakes with Retry and circuit breaker?
Retrying non-idempotent operations. No backoff or jitter, so retries arrive in a synchronized wave. Retrying calls that have no timeout. A fallback that hides failures completely. Calling the annotated method from within the same class.
How can I see Retry and circuit breaker in real code?
Paste your own Java into Unravel and it will point out where retry and circuit breaker appears, explain how it works at the detail level you choose, and draw the flow of the code around it.