Prev Next

Spring / Resilience4j Interview questions

1. What is Resilience4j? 2. What are the core modules of Resilience4j? 3. What is a Circuit Breaker in Resilience4j? 4. What are the states of a CircuitBreaker? 5. What is the Retry module used for? 6. What is a RateLimiter in Resilience4j? 7. What is the Bulkhead pattern in Resilience4j? 8. What is a TimeLimiter in Resilience4j? 9. What is the Cache module in Resilience4j? 10. How do you add Resilience4j to a Spring Boot project? 11. What is the purpose of the Decorators class? 12. Define fallback method in Resilience4j? 13. What are the types of Bulkhead implementations? 14. List the key configuration properties of a CircuitBreaker? 15. How do you apply @CircuitBreaker in a Spring Boot service? 16. Why is Resilience4j often preferred over Hystrix? 17. How does the sliding window work in CircuitBreaker? 18. What is the difference between COUNT_BASED and TIME_BASED sliding windows? 19. How is failure rate calculated in a CircuitBreaker? 20. What is the difference between CircuitBreaker and Bulkhead? 21. How does the half-open state behave in a CircuitBreaker? 22. Why do we use recordExceptions versus ignoreExceptions? 23. When should you use RateLimiter instead of Bulkhead? 24. What happens when a CircuitBreaker transitions to OPEN? 25. How is Resilience4j's Retry different from a plain retry loop? 26. Explain the execution flow of a call decorated with CircuitBreaker, Retry, and Bulkhead together? 27. How do you combine multiple Resilience4j decorators using the Decorators class? 28. Which is better and why: SemaphoreBulkhead or ThreadPoolBulkhead? 29. How can you optimize CircuitBreaker configuration for a high-throughput service? 30. How do you troubleshoot a CircuitBreaker that never opens despite failures? 31. Explain the lifecycle of a CircuitBreaker instance? 32. What is the difference between TimeLimiter and a plain timeout? 33. How does RegistryEventConsumer work in Resilience4j? 34. Why does Resilience4j rely on functional interfaces like Supplier and Function? 35. How do you monitor Resilience4j metrics with Micrometer? 36. What is the difference between waitDurationInOpenState and permittedNumberOfCallsInHalfOpenState? 37. How do you write a unit test for a CircuitBreaker-protected method? 38. Explain the internal working of exponential backoff in the Retry module? 39. What is the difference between CallNotPermittedException and other Resilience4j exceptions? 40. How do you use event publishers to log CircuitBreaker state transitions? 41. When would you choose a RateLimiter over a Bulkhead for protecting a downstream call? 42. How does Resilience4j integrate with reactive streams in WebFlux? 43. What is the difference between recordException and recordResult predicates? 44. Explain the internal working of automaticTransitionFromOpenToHalfOpenEnabled? 45. How do you configure Resilience4j using application.yml in Spring Boot? 46. What is the difference between the Resilience4j Cache module and a plain in-memory cache like Guava? 47. How can you optimize retry strategies to avoid retry storms? 48. Explain the execution flow when a fallback method itself throws an exception? 49. How do you troubleshoot memory growth caused by an unbounded ThreadPoolBulkhead queue? 50. Explain how Resilience4j's modular design influences microservice resilience architecture at scale?

1. What is Resilience4j?

Resilience4j is a lightweight fault-tolerance library for Java 8 and above, built around functional programming rather than the class-heavy wrapper style of its predecessor, Netflix Hystrix. Instead of forcing every protected call through a dedicated command class, it decorates plain Supplier , F...

Read full answer

2. What are the core modules of Resilience4j?

Resilience4j is organized into a handful of focused modules, each one implementing a single resilience pattern that can be added to a project independently. Module Purpose CircuitBreaker Stops calling a failing dependency for a cooldown period. Retry Re-executes a failed call a bounded number of ...

Read full answer

3. What is a Circuit Breaker in Resilience4j?

A CircuitBreaker wraps a call to a potentially failing dependency and stops sending traffic to it once failures cross a configured threshold, instead of letting every caller keep waiting on a service that's already struggling. It works like an electrical circuit breaker: normal traffic flows thro...

Read full answer

4. What are the states of a CircuitBreaker?

A Resilience4j CircuitBreaker moves through several distinct states rather than just "on" or "off". CLOSED - calls pass through normally and results feed the failure-rate calculation. OPEN - calls are rejected immediately without touching the dependency. HALF_OPEN - a limited number of trial call...

Read full answer

5. What is the Retry module used for?

The Retry module re-executes a call that failed or returned an undesirable result, up to a configured number of attempts, instead of surfacing a transient failure straight to the caller. It's configured with a maxAttempts count and a waitDuration (or an IntervalFunction for backoff) between attem...

Read full answer

6. What is a RateLimiter in Resilience4j?

A RateLimiter caps how many calls are allowed to proceed within a fixed time window, rejecting or delaying calls beyond that limit rather than letting demand spike freely against a dependency. It's configured with limitForPeriod (how many calls are permitted per window), limitRefreshPeriod (how l...

Read full answer

7. What is the Bulkhead pattern in Resilience4j?

Bulkhead limits how many calls to a specific dependency can run at the same time, so one slow or misbehaving dependency can't consume every available thread and starve unrelated calls. The name comes from ship design, where watertight compartments (bulkheads) stop a single hull breach from sinkin...

Read full answer

8. What is a TimeLimiter in Resilience4j?

TimeLimiter enforces a maximum duration on an asynchronous call, throwing a TimeoutException if the call hasn't completed once the configured timeoutDuration passes. It's designed to work with CompletionStage or Future -returning calls rather than plain synchronous ones, since it needs an async h...

Read full answer

9. What is the Cache module in Resilience4j?

The Cache module wraps a function call so that a previously computed result for the same input is returned directly, skipping the actual call entirely on a cache hit. It's built on top of the JSR-107 (JCache) specification, so it needs an actual JCache provider - such as Ehcache - configured unde...

Read full answer

10. How do you add Resilience4j to a Spring Boot project?

Add the Spring Boot starter for the modules you need - typically io.github.resilience4j:resilience4j-spring-boot3 for Spring Boot 3, plus Spring's own spring-boot-starter-aop , since Resilience4j's annotations rely on Spring AOP proxies to intercept calls. io.github.resilie...

Read full answer

11. What is the purpose of the Decorators class?

The Decorators class provides a fluent builder for composing multiple resilience patterns around a single call, without hand-nesting one decorator function inside another. Instead of writing CircuitBreaker.decorateSupplier(cb, RateLimiter.decorateSupplier(rl, supplier)) by hand, you write Decorat...

Read full answer

12. Define fallback method in Resilience4j?

A fallback is an alternate code path that runs when the primary, resilience-wrapped call fails or is rejected, so the caller gets a usable result instead of a raw exception. With the functional API this is done via Try.of(supplier).recover(throwable -> fallbackValue) or Decorators...withFallback(...

Read full answer

13. What are the types of Bulkhead implementations?

Resilience4j offers two Bulkhead implementations, and choosing between them matters more than most other configuration decisions in the module. SemaphoreBulkhead ThreadPoolBulkhead Limits concurrent calls using a semaphore on the caller's own thread. Runs calls on a separate, bounded thread pool ...

Read full answer

14. List the key configuration properties of a CircuitBreaker?

failureRateThreshold - percentage of failed calls that trips the breaker to OPEN. slowCallRateThreshold / slowCallDurationThreshold - treat calls slower than a duration as failures too. slidingWindowType / slidingWindowSize - COUNT_BASED or TIME_BASED window used to compute the rate. minimumNumbe...

Read full answer

15. How do you apply @CircuitBreaker in a Spring Boot service?

Annotate the method that makes the risky call with @CircuitBreaker(name = "paymentService", fallbackMethod = "paymentFallback") , and Spring AOP wraps it in a proxy that routes the call through the named CircuitBreaker instance. @CircuitBreaker (name = "paymentService" , fallbackMethod = "payment...

Read full answer

16. Why is Resilience4j often preferred over Hystrix?

Hystrix was put into maintenance mode by Netflix in 2018, so Resilience4j is preferred today largely because it's the actively maintained option, with regular releases and support for current Java versions and frameworks that Hystrix never received. Architecturally, Resilience4j is built on plain...

Read full answer

17. How does the sliding window work in CircuitBreaker?

The sliding window is the pool of most recent call outcomes the CircuitBreaker uses to calculate its failure rate and slow-call rate, rather than looking at the entire call history since startup. In COUNT_BASED mode, the window holds a fixed number of the most recent calls - for example, the last...

Read full answer

18. What is the difference between COUNT_BASED and TIME_BASED sliding windows?

COUNT_BASED TIME_BASED Window holds a fixed number of the last N calls. Window holds calls from the last N seconds. Rate stays stable regardless of traffic bursts. Rate can shift quickly during traffic spikes or lulls. Simple to reason about for steady, predictable traffic. Better reflects real-t...

Read full answer

19. How is failure rate calculated in a CircuitBreaker?

The failure rate is the percentage of calls in the current sliding window that either threw a recorded exception or exceeded the slow-call duration threshold, measured once enough calls have accumulated to satisfy minimumNumberOfCalls . Concretely: if the window holds 100 calls and 40 of them fai...

Read full answer

20. What is the difference between CircuitBreaker and Bulkhead?

CircuitBreaker and Bulkhead solve different problems even though both protect calls to a dependency: CircuitBreaker reacts to a dependency already failing or running slow, while Bulkhead limits how many calls can run concurrently regardless of whether they're failing at all. A CircuitBreaker look...

Read full answer

21. How does the half-open state behave in a CircuitBreaker?

HALF_OPEN is a probationary state the breaker enters after waitDurationInOpenState elapses, meant to test whether the dependency has actually recovered before fully reopening traffic. Only permittedNumberOfCallsInHalfOpenState trial calls are allowed through; every other call is still rejected ex...

Read full answer

22. Why do we use recordExceptions versus ignoreExceptions?

Both control which thrown exceptions the CircuitBreaker counts as a failure, but they express the intent from opposite directions and are meant to be used situationally, not both at once for the same exception. recordExceptions is an allow-list: only the listed exception types (and their subclass...

Read full answer

23. When should you use RateLimiter instead of Bulkhead?

Use RateLimiter when the constraint is a rate over time - calls per second or per minute - such as respecting a third-party API's documented rate limit or protecting a downstream system from a traffic burst. Use Bulkhead instead when the constraint is concurrency at any given instant - how many c...

Read full answer

24. What happens when a CircuitBreaker transitions to OPEN?

The moment the failure or slow-call rate crosses its threshold, the breaker immediately switches to OPEN and every subsequent call is rejected with a CallNotPermittedException instead of being attempted against the dependency at all. Any fallback method configured alongside the CircuitBreaker sti...

Read full answer

25. How is Resilience4j's Retry different from a plain retry loop?

A hand-rolled retry loop usually just wraps a call in a for-loop with a try/catch and a fixed sleep, which works but scatters retry logic across the codebase and makes it hard to reason about consistently. Resilience4j's Retry centralizes that behavior in a named, reusable Retry instance with con...

Read full answer

26. Explain the execution flow of a call decorated with CircuitBreaker, Retry, and Bulkhead together?

When these three are composed, the order they're applied in determines which one "sees" the call first, and getting that order wrong changes the actual behavior even though the code looks similar either way. The generally recommended order is Bulkhead (outermost) → CircuitBreaker → Re...

Read full answer

27. How do you combine multiple Resilience4j decorators using the Decorators class?

The Decorators class chains .withX() calls onto a base Supplier , Function , or similar functional type, then materializes the whole composition with .decorate() . Supplier decorated = Decorators.ofSupplier(() -> remoteCall()) .withBulkhead(bulkhead) .withCircuitBreaker(circuitBreaker) .w...

Read full answer

28. Which is better and why: SemaphoreBulkhead or ThreadPoolBulkhead?

Neither is universally "better" - they suit different situations, and the choice mostly comes down to whether the protected call is synchronous/blocking or needs true interruption on timeout. SemaphoreBulkhead is lighter weight: it limits concurrency using a plain semaphore on the caller's own th...

Read full answer

29. How can you optimize CircuitBreaker configuration for a high-throughput service?

On a high-throughput service, a COUNT_BASED sliding window with a reasonably large size (for example, 200-1000 calls) usually gives a more stable failure-rate signal than TIME_BASED, since traffic volume is already consistent enough that a count window won't lag behind reality. Set minimumNumberO...

Read full answer

30. How do you troubleshoot a CircuitBreaker that never opens despite failures?

First check minimumNumberOfCalls against actual traffic - if it's set higher than the real call volume in the current sliding window, the failure rate is never even evaluated, so the breaker can't open no matter how bad things get. Next verify the exception being thrown is actually being recorded...

Read full answer

31. Explain the lifecycle of a CircuitBreaker instance?

A CircuitBreaker instance is created by name from a CircuitBreakerRegistry - either the default shared registry or one built from custom CircuitBreakerConfig - and it starts in the CLOSED state with an empty sliding window. As calls flow through it, each outcome (success, failure, or slow call) i...

Read full answer

32. What is the difference between TimeLimiter and a plain timeout?

A plain, hand-written timeout - like calling future.get(5, TimeUnit.SECONDS) directly - throws when the deadline passes, but the underlying task usually keeps running on its own thread unless something else explicitly cancels it, which can silently leak resources over time. Resilience4j's TimeLim...

Read full answer

33. How does RegistryEventConsumer work in Resilience4j?

RegistryEventConsumer lets code react to changes at the registry level - when a CircuitBreaker (or Retry, Bulkhead, etc.) instance is added, removed, or replaced in its registry - rather than reacting to individual call events on one specific instance. It's implemented by overriding onEntryAddedE...

Read full answer

34. Why does Resilience4j rely on functional interfaces like Supplier and Function?

Building around Supplier , Function , Runnable , Callable , and CompletionStage means Resilience4j can decorate any piece of existing code that already fits one of those shapes, without requiring it to extend a base class or implement a library-specific command interface the way Hystrix's Hystrix...

Read full answer

35. How do you monitor Resilience4j metrics with Micrometer?

The resilience4j-micrometer module exposes each registry's metrics by binding it directly to a Micrometer MeterRegistry , after which Micrometer's usual exporters (Prometheus, Datadog, CloudWatch, etc.) pick the data up like any other application metric. TaggedCircuitBreakerMetrics .ofCircuitBrea...

Read full answer

36. What is the difference between waitDurationInOpenState and permittedNumberOfCallsInHalfOpenState?

These two settings control different phases of recovery and are easy to conflate since they both govern "what happens after the breaker opens". waitDurationInOpenState is a time value - how long the breaker stays fully OPEN, rejecting every call, before it's even eligible to move to HALF_OPEN and...

Read full answer

37. How do you write a unit test for a CircuitBreaker-protected method?

Build the CircuitBreaker from an explicit, test-specific CircuitBreakerConfig rather than relying on the application's real application.yml values, so the test controls thresholds directly instead of depending on production configuration that might change independently. CircuitBreakerConfig confi...

Read full answer

38. Explain the internal working of exponential backoff in the Retry module?

Exponential backoff increases the wait time between successive retry attempts rather than using the same fixed delay every time, which spreads out repeated load on a struggling dependency instead of hammering it at a constant rate. Resilience4j implements this through the IntervalFunction abstrac...

Read full answer

39. What is the difference between CallNotPermittedException and other Resilience4j exceptions?

Exception Thrown by / meaning CallNotPermittedException CircuitBreaker is OPEN; the call was never attempted. BulkheadFullException Bulkhead concurrency/queue limit reached; call rejected before running. RequestNotPermitted RateLimiter's permit timeout expired; call was never attempted. TimeoutEx...

Read full answer

40. How do you use event publishers to log CircuitBreaker state transitions?

circuitBreaker.getEventPublisher() .onStateTransition(event -> log.info("CB '{}' transitioned {} -> {}", event.getCircuitBreakerName(), event.getStateTransition().getFromState(), event.getStateTransition().getToState())) .onCallNotPermitted(event -> log.warn("Call rejected: CB '{}' is OPEN", even...

Read full answer

41. When would you choose a RateLimiter over a Bulkhead for protecting a downstream call?

Choose RateLimiter when the actual constraint you're protecting against is expressed as a rate - a third-party API that documents "100 requests per minute", or a downstream system whose own capacity planning is expressed in requests-per-second, not in how many requests can be in flight at once. B...

Read full answer

42. How does Resilience4j integrate with reactive streams in WebFlux?

The resilience4j-reactor module supplies operators - CircuitBreakerOperator , RetryOperator , RateLimiterOperator , BulkheadOperator , TimeLimiterOperator - that plug into a Mono or Flux pipeline via .transformDeferred(...) , rather than wrapping a blocking Supplier the way the core modules do. M...

Read full answer

43. What is the difference between recordException and recordResult predicates?

A recordExceptionPredicate decides, based on the exception a call threw, whether that particular exception should count as a failure - useful when the exception type alone (say, a checked wrapper) doesn't tell the whole story and the predicate needs to inspect the exception's cause or message. A ...

Read full answer

44. Explain the internal working of automaticTransitionFromOpenToHalfOpenEnabled?

By default this flag is false, which means the CircuitBreaker doesn't proactively schedule a background timer to flip itself from OPEN to HALF_OPEN - instead, the transition is evaluated lazily, checked only when the next call actually arrives after waitDurationInOpenState has elapsed. Setting it...

Read full answer

45. How do you configure Resilience4j using application.yml in Spring Boot?

resilience4j: circuitbreaker: instances: paymentService: slidingWindowSize: 20 failureRateThreshold: 50 waitDurationInOpenState: 10s permittedNumberOfCallsInHalfOpenState: 5 retry: instances: paymentService: maxAttempts: 3 waitDuration: 500ms bulkhead: instances: paymentService: maxConcurrentCall...

Read full answer

46. What is the difference between the Resilience4j Cache module and a plain in-memory cache like Guava?

Guava's Cache is a general-purpose, standalone in-memory cache: you put and get arbitrary key-value pairs directly, with eviction policies like size limits or expiry, entirely independent of any resilience concerns. Resilience4j's Cache module is narrower by design - it's a decorator specifically...

Read full answer

47. How can you optimize retry strategies to avoid retry storms?

A retry storm happens when many clients (or many concurrent requests on one client) all retry a failing dependency at roughly the same moments, effectively multiplying the load on a system that's already struggling and making recovery harder instead of easier. Use IntervalFunction.ofExponentialRa...

Read full answer

48. Explain the execution flow when a fallback method itself throws an exception?

If the fallback method itself throws, Resilience4j doesn't retry the fallback or fall back to a "fallback of the fallback" automatically - the exception thrown by the fallback simply propagates to the caller as-is, since fallback logic is treated as ordinary application code once control reaches ...

Read full answer

49. How do you troubleshoot memory growth caused by an unbounded ThreadPoolBulkhead queue?

Check the configured queueCapacity first - if it's left very large or effectively unbounded while the downstream dependency is slow, incoming calls pile up in the queue faster than the pool can drain them, and each queued task holds onto memory (its captured state, any request payload) until it's...

Read full answer

50. Explain how Resilience4j's modular design influences microservice resilience architecture at scale?

Because each pattern - CircuitBreaker, Retry, Bulkhead, RateLimiter, TimeLimiter, Cache - lives in its own module, teams can adopt resilience incrementally rather than needing to buy into a heavyweight, all-or-nothing framework before getting any protection at all; a service can start with just C...

Read full answer

«
»

Comments & Discussions