[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-4098":3},{"id":4,"name":5,"fullName":6,"owner":5,"repo":5,"description":7,"homepage":8,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":15,"forks30d":15,"starsTrendScore":19,"compositeScore":20,"rankGlobal":9,"rankLanguage":9,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":22,"hasPages":24,"topics":25,"createdAt":9,"pushedAt":9,"updatedAt":32,"readmeContent":33,"aiSummary":34,"trendingCount":15,"starSnapshotCount":15,"syncStatus":16,"lastSyncTime":35,"discoverSource":36},4098,"resilience4j","resilience4j\u002Fresilience4j","Resilience4j is a fault tolerance library designed for Java8 and functional programming","",null,"Java",10683,1466,214,255,0,2,6,30,8,44.5,"Apache License 2.0",false,"master",true,[26,27,28,29,30,31],"bulkhead","circuitbreaker","metrics","rate-limiter","resilience","retry","2026-06-12 02:00:58","= Fault tolerance library designed for functional programming\n:author: Robert Winkler and Bohdan Storozhuk\n:icons:\n:toc: macro\n:numbered: 1\nifdef::env-github[]\n:tip-caption: :bulb:\n:note-caption: :information_source:\n:important-caption: :heavy_exclamation_mark:\n:caution-caption: :fire:\n:warning-caption: :warning:\nendif::[]\n\nimage:https:\u002F\u002Fgithub.com\u002Fresilience4j\u002Fresilience4j\u002Factions\u002Fworkflows\u002Fgradle-build.yml\u002Fbadge.svg[\"Build Status\"]\nimage:https:\u002F\u002Fimg.shields.io\u002Fnexus\u002Fr\u002Fio.github.resilience4j\u002Fresilience4j-circuitbreaker?server=https%3A%2F%2Foss.sonatype.org[\"Release\"]\nimage:https:\u002F\u002Fimg.shields.io\u002Fnexus\u002Fs\u002Fio.github.resilience4j\u002Fresilience4j-circuitbreaker?server=https%3A%2F%2Foss.sonatype.org[\"Snapshot\"]\nimage:http:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-ASF2-blue.svg[\"Apache License 2\", link=\"http:\u002F\u002Fwww.apache.org\u002Flicenses\u002FLICENSE-2.0.txt\"]\n\nimage:https:\u002F\u002Fsonarcloud.io\u002Fapi\u002Fproject_badges\u002Fmeasure?project=resilience4j_resilience4j&metric=coverage[\"Coverage\", link=\"https:\u002F\u002Fsonarcloud.io\u002Fdashboard?id=resilience4j_resilience4j\"]\nimage:https:\u002F\u002Fsonarcloud.io\u002Fapi\u002Fproject_badges\u002Fmeasure?project=resilience4j_resilience4j&metric=sqale_rating[\"Maintainability\", link=\"https:\u002F\u002Fsonarcloud.io\u002Fdashboard?id=resilience4j_resilience4j\"]\nimage:https:\u002F\u002Fsonarcloud.io\u002Fapi\u002Fproject_badges\u002Fmeasure?project=resilience4j_resilience4j&metric=reliability_rating[\"Reliability\", link=\"https:\u002F\u002Fsonarcloud.io\u002Fdashboard?id=resilience4j_resilience4j\"]\nimage:https:\u002F\u002Fsonarcloud.io\u002Fapi\u002Fproject_badges\u002Fmeasure?project=resilience4j_resilience4j&metric=security_rating[\"Security\", link=\"https:\u002F\u002Fsonarcloud.io\u002Fdashboard?id=resilience4j_resilience4j\"]\nimage:https:\u002F\u002Fsonarcloud.io\u002Fapi\u002Fproject_badges\u002Fmeasure?project=resilience4j_resilience4j&metric=vulnerabilities[\"Vulnerabilities\", link=\"https:\u002F\u002Fsonarcloud.io\u002Fdashboard?id=resilience4j_resilience4j\"]\nimage:https:\u002F\u002Fsonarcloud.io\u002Fapi\u002Fproject_badges\u002Fmeasure?project=resilience4j_resilience4j&metric=bugs[\"Bugs\", link=\"https:\u002F\u002Fsonarcloud.io\u002Fdashboard?id=resilience4j_resilience4j\"]\n\nimage:https:\u002F\u002Fraw.githubusercontent.com\u002Fvshymanskyy\u002FStandWithUkraine\u002Fmain\u002Fbanner2-direct.svg[\"SWUbanner\",link=\"https:\u002F\u002Fvshymanskyy.github.io\u002FStandWithUkraine\"]\n\ntoc::[]\n\n== Introduction\n\nResilience4j is a lightweight fault tolerance library designed for functional programming.\nResilience4j provides higher-order functions (decorators) to enhance any functional interface,\nlambda expression or method reference with a Circuit Breaker, Rate Limiter, Retry or Bulkhead.\nYou can stack more than one decorator on any functional interface, lambda expression or method reference.\nThe advantage is that you have the choice to select the decorators you need and nothing else.\n\nResilience4j 3 requires Java 21.\n\n[source,java]\n----\n\u002F\u002F Create a CircuitBreaker with default configuration\nCircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults(\"backendService\");\n\n\u002F\u002F Create a Retry with default configuration\n\u002F\u002F 3 retry attempts and a fixed time interval between retries of 500ms\nRetry retry = Retry.ofDefaults(\"backendService\");\n\n\u002F\u002F Create a Bulkhead with default configuration\nBulkhead bulkhead = Bulkhead.ofDefaults(\"backendService\");\n\nSupplier\u003CString> supplier = () -> backendService\n  .doSomething(param1, param2);\n\n\u002F\u002F Decorate your call to backendService.doSomething()\n\u002F\u002F with a Bulkhead, CircuitBreaker and Retry\n\u002F\u002F **note: you will need the resilience4j-all dependency for this\nSupplier\u003CString> decoratedSupplier = Decorators.ofSupplier(supplier)\n  .withCircuitBreaker(circuitBreaker)\n  .withBulkhead(bulkhead)\n  .withRetry(retry)\n  .decorate();\n\n\u002F\u002F Execute the decorated supplier and recover from any exception\nString result = Try.ofSupplier(decoratedSupplier)\n  .recover(throwable -> \"Hello from Recovery\").get();\n\n\u002F\u002F When you don't want to decorate your lambda expression,\n\u002F\u002F but just execute it and protect the call by a CircuitBreaker.\nString result = circuitBreaker\n  .executeSupplier(backendService::doSomething);\n\n\u002F\u002F You can also run the supplier asynchronously in a ThreadPoolBulkhead\n ThreadPoolBulkhead threadPoolBulkhead = ThreadPoolBulkhead\n  .ofDefaults(\"backendService\");\n\n\u002F\u002F The Scheduler is needed to schedule a timeout on a non-blocking CompletableFuture\nScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3);\nTimeLimiter timeLimiter = TimeLimiter.of(Duration.ofSeconds(1));\n\nCompletableFuture\u003CString> future = Decorators.ofSupplier(supplier)\n    .withThreadPoolBulkhead(threadPoolBulkhead)\n    .withTimeLimiter(timeLimiter, scheduler)\n    .withCircuitBreaker(circuitBreaker)\n    .withFallback(asList(TimeoutException.class, CallNotPermittedException.class, BulkheadFullException.class),\n      throwable -> \"Hello from Recovery\")\n    .get().toCompletableFuture();\n----\n\nNOTE: With Resilience4j you don’t have to go all-in, you can\nhttps:\u002F\u002Fmvnrepository.com\u002Fartifact\u002Fio.github.resilience4j[*pick what you need*].\n\n==  Documentation\n\nSetup and usage is described in our *https:\u002F\u002Fresilience4j.readme.io\u002Fdocs[User Guide]*.\n\n- https:\u002F\u002Fgithub.com\u002Fresilience4j-docs-ja\u002Fresilience4j-docs-ja[有志による日本語訳(非公式) Japanese translation by volunteers(Unofficial)]\n\n- https:\u002F\u002Fgithub.com\u002Flmhmhl\u002FResilience4j-Guides-Chinese[这是Resilience4j的非官方中文文档 Chinese translation by volunteers(Unofficial)]\n\n== Overview\n\nResilience4j provides several core modules:\n\n* resilience4j-circuitbreaker: Circuit breaking\n* resilience4j-ratelimiter: Rate limiting\n* resilience4j-bulkhead: Bulkheading\n* resilience4j-retry: Automatic retrying (sync and async)\n* resilience4j-timelimiter: Timeout handling\n* resilience4j-cache: Result caching\n\nThere are also add-on modules for metrics, Feign, Kotlin, Spring, Ratpack, Vertx, RxJava2 and more.\n\nNOTE: Find out full list of modules in our *https:\u002F\u002Fresilience4j.readme.io\u002Fdocs#section-modularization[User Guide]*.\n\nTIP: For core modules package or `+Decorators+` builder see *https:\u002F\u002Fmvnrepository.com\u002Fartifact\u002Fio.github.resilience4j\u002Fresilience4j-all[resilience4j-all]*.\n\n== Best Practices\n\n=== Instance Management: When to Share vs. Not Share Instances\n\nOne of the most important concepts for newcomers to understand is when to create separate instances versus when to share instances across different remote services or backends.\n\n[IMPORTANT]\n====\n*The Golden Rule:* Create a unique instance (with a unique ID) for each protected remote service or backend you communicate with.\n====\n\n==== Why Unique Instances Matter\n\nCreating separate instances for each backend service is critical for:\n\n1. *Proper metrics collection* - Each instance tracks its own metrics, allowing you to monitor the health of individual services\n2. *Isolation of failures* - If Service A fails, it won't affect the resilience patterns protecting Service B\n3. *Independent configuration* - Different backends may require different circuit breaker thresholds, concurrency limits, rate limits, or retry policies\n\n==== Instance-Aware vs. Non-Instance-Aware Patterns\n\nDifferent resilience patterns have different requirements for instance separation:\n\n===== Instance-Aware Patterns (MUST NOT Share)\n\nThese patterns maintain state that is specific to a particular service and *MUST* have separate instances:\n\n* *CircuitBreaker* - Tracks failure rates and state (OPEN\u002FCLOSED\u002FHALF_OPEN) per service\n+\n[source,java]\n----\n\u002F\u002F CORRECT: Separate CircuitBreaker for each service\nCircuitBreaker paymentServiceCB = CircuitBreaker.ofDefaults(\"paymentService\");\nCircuitBreaker inventoryServiceCB = CircuitBreaker.ofDefaults(\"inventoryService\");\nCircuitBreaker notificationServiceCB = CircuitBreaker.ofDefaults(\"notificationService\");\n\n\u002F\u002F WRONG: Sharing one CircuitBreaker across multiple services\nCircuitBreaker sharedCB = CircuitBreaker.ofDefaults(\"shared\"); \u002F\u002F DON'T DO THIS!\n\u002F\u002F If one service fails, the circuit opens for ALL services!\n----\n\n* *Bulkhead* (both SemaphoreBulkhead and ThreadPoolBulkhead) - Manages concurrent call limits per service\n+\n[source,java]\n----\n\u002F\u002F CORRECT: Separate Bulkhead for each service\nBulkhead paymentBulkhead = Bulkhead.ofDefaults(\"paymentService\");\nBulkhead inventoryBulkhead = Bulkhead.ofDefaults(\"inventoryService\");\n\n\u002F\u002F WRONG: Sharing limits resource isolation benefits\nBulkhead sharedBulkhead = Bulkhead.ofDefaults(\"shared\"); \u002F\u002F DON'T DO THIS!\n----\n\n* *RateLimiter* - Controls request rate per service\n+\n[source,java]\n----\n\u002F\u002F CORRECT: Different rate limits for different services\nRateLimiter apiRateLimiter = RateLimiter.ofDefaults(\"externalAPI\");\nRateLimiter dbRateLimiter = RateLimiter.ofDefaults(\"database\");\n----\n\n===== Non-Instance-Aware Patterns (CAN Share, But Better Not To)\n\nThese patterns create fresh context for each execution and don't maintain service-specific state:\n\n* *Retry* - Configuration can be shared, but unique instances are still recommended for proper metrics\n* *TimeLimiter* - Timeout settings can be shared if identical across services\n\n[source,java]\n----\n\u002F\u002F TECHNICALLY OK: Retry doesn't maintain state between calls\nRetry sharedRetry = Retry.ofDefaults(\"shared\");\n\n\u002F\u002F BETTER: Unique instances provide better metrics and monitoring\nRetry paymentRetry = Retry.ofDefaults(\"paymentService\");\nRetry inventoryRetry = Retry.ofDefaults(\"inventoryService\");\n\n\u002F\u002F Now you can track:\n\u002F\u002F - How many retry attempts failed for paymentService specifically\n\u002F\u002F - How many retry attempts failed for inventoryService specifically\n----\n\n==== Recommended Approach: Always Use Unique Instances\n\nEven for patterns that *can* be shared, creating unique instances is the recommended approach because:\n\n* *Better observability* - Metrics are tagged by instance name, letting you see which backend is struggling\n* *Easier troubleshooting* - Clear separation makes debugging production issues simpler\n* *Future flexibility* - If you later need different configurations per service, instances are already separated\n\n===== Complete Example: Multiple Services\n\n[source,java]\n----\n\u002F\u002F You have 3 backend services to protect\npublic class ServiceOrchestrator {\n\n    \u002F\u002F Payment Service protection\n    private final CircuitBreaker paymentCB = CircuitBreaker.ofDefaults(\"paymentService\");\n    private final Retry paymentRetry = Retry.ofDefaults(\"paymentService\");\n    private final Bulkhead paymentBulkhead = Bulkhead.ofDefaults(\"paymentService\");\n\n    \u002F\u002F Inventory Service protection\n    private final CircuitBreaker inventoryCB = CircuitBreaker.ofDefaults(\"inventoryService\");\n    private final Retry inventoryRetry = Retry.ofDefaults(\"inventoryService\");\n    private final Bulkhead inventoryBulkhead = Bulkhead.ofDefaults(\"inventoryService\");\n\n    \u002F\u002F Notification Service protection\n    private final CircuitBreaker notificationCB = CircuitBreaker.ofDefaults(\"notificationService\");\n    private final Retry notificationRetry = Retry.ofDefaults(\"notificationService\");\n\n    public Order processOrder(OrderRequest request) {\n        \u002F\u002F Each service call is protected by its own set of resilience instances\n\n        \u002F\u002F Call payment service\n        Supplier\u003CPaymentResult> paymentCall = () -> paymentService.charge(request);\n        PaymentResult payment = Decorators.ofSupplier(paymentCall)\n            .withCircuitBreaker(paymentCB)\n            .withRetry(paymentRetry)\n            .withBulkhead(paymentBulkhead)\n            .decorate()\n            .get();\n\n        \u002F\u002F Call inventory service\n        Supplier\u003CInventoryResult> inventoryCall = () -> inventoryService.reserve(request);\n        InventoryResult inventory = Decorators.ofSupplier(inventoryCall)\n            .withCircuitBreaker(inventoryCB)\n            .withRetry(inventoryRetry)\n            .withBulkhead(inventoryBulkhead)\n            .decorate()\n            .get();\n\n        \u002F\u002F Call notification service (demonstrates circuit isolation: the notification circuit breaker remains independent of the payment circuit breaker, even if payment opens its circuit in other calls)\n        Runnable notificationCall = () -> notificationService.send(request);\n        Decorators.ofRunnable(notificationCall)\n            .withCircuitBreaker(notificationCB)\n            .withRetry(notificationRetry)\n            .decorate()\n            .run();\n\n        return new Order(payment, inventory);\n    }\n}\n----\n\n==== Using Registries for Instance Management\n\nResilience4j provides Registry classes to manage multiple instances efficiently:\n\n[source,java]\n----\n\u002F\u002F Create a registry with custom default configuration\nCircuitBreakerConfig defaultConfig = CircuitBreakerConfig.custom()\n    .failureRateThreshold(50)\n    .waitDurationInOpenState(Duration.ofSeconds(30))\n    .build();\n\nCircuitBreakerRegistry registry = CircuitBreakerRegistry.of(defaultConfig);\n\n\u002F\u002F Get or create instances by name\nCircuitBreaker paymentCB = registry.circuitBreaker(\"paymentService\");\nCircuitBreaker inventoryCB = registry.circuitBreaker(\"inventoryService\");\n\n\u002F\u002F You can also override config for specific instances\nCircuitBreakerConfig customConfig = CircuitBreakerConfig.custom()\n    .failureRateThreshold(80)  \u002F\u002F More lenient for this service\n    .build();\nCircuitBreaker legacyCB = registry.circuitBreaker(\"legacyService\", customConfig);\n----\n\nNOTE: Registries are particularly useful in Spring Boot applications where they're auto-configured and instances are created on-demand based on configuration properties.\n\n==== Summary\n\n[cols=\"\u003C.\u003C*\", options=\"header\"]\n|===\n|Pattern |Can Share? |Should Share? |Why?\n\n|*CircuitBreaker*\n|No\n|No\n|State is service-specific. Sharing causes one service's failures to affect all others.\n\n|*Bulkhead*\n|No\n|No\n|Concurrent call limits must be isolated per service for proper resource management.\n\n|*RateLimiter*\n|No\n|No\n|Rate limits are typically different per service and sharing defeats the purpose.\n\n|*Retry*\n|Yes\n|No\n|While technically safe to share, unique instances provide better metrics and observability.\n\n|*TimeLimiter*\n|Yes\n|No\n|While technically safe to share, unique instances provide better metrics and observability.\n\n|*Cache*\n|Depends\n|Depends\n|Only share if the cached data is truly identical across use cases.\n\n|===\n\n[TIP]\n====\nWhen in doubt, create separate instances. The overhead is minimal, and the benefits for metrics, debugging, and flexibility are significant.\n====\n\n== Resilience patterns\n\n[cols=\"\u003C.\u003C*\", options=\"header\"]\n|===\n|name |how does it work? |description |links\n\n|*Retry*\n|repeats failed executions\n|Many faults are transient and may self-correct after a short delay.\n|\u003C\u003Ccircuitbreaker-retry-fallback,overview>>,\nhttps:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Fretry[documentation],\nhttps:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Fgetting-started-3#annotations[Spring]\n\n|**Circuit Breaker**\n|temporary blocks possible failures\n|When a system is seriously struggling, failing fast is better than making clients wait.\n|\u003C\u003Ccircuitbreaker-retry-fallback,overview>>,\nhttps:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Fcircuitbreaker[documentation],\nhttps:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Ffeign[Feign],\nhttps:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Fgetting-started-3#annotations[Spring]\n\n|**Rate Limiter**\n|limits executions\u002Fperiod\n|Limit the rate of incoming requests.\n|\u003C\u003Cratelimiter,overview>>,\nhttps:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Fratelimiter[documentation],\nhttps:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Ffeign[Feign],\nhttps:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Fgetting-started-3#annotations[Spring]\n\n|**Time Limiter**\n|limits duration of execution\n|Beyond a certain wait interval, a successful result is unlikely.\n|https:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Ftimeout[documentation],\nhttps:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Fgetting-started-3#annotations[Spring]\n\n|**Bulkhead**\n|limits concurrent executions\n|Resources are isolated into pools so that if one fails, the others will continue working.\n|\u003C\u003Cbulkhead,overview>>,\nhttps:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Fbulkhead[documentation],\nhttps:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Fgetting-started-3#annotations[Spring]\n\n|**Cache**\n|memorizes a successful result\n|Some proportion of requests may be similar.\n|https:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Fcache[documentation]\n\n|**Fallback**\n|provides an alternative result for failures\n|Things will still fail - plan what you will do when that happens.\n|\u003C\u003Ccircuitbreaker-retry-fallback,Try::recover>>,\nhttps:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Fgetting-started-3#section-annotations[Spring],\nhttps:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Ffeign[Feign]\n\n|===\n\n_Above table is based on https:\u002F\u002Fgithub.com\u002FApp-vNext\u002FPolly#resilience-policies[Polly: resilience policies]._\n\nNOTE: To find more information about resilience patterns check link:#Talks[*Talks*] section.\nFind out more about components in our *https:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Fgetting-started-2[User Guide]*.\n\n== Spring Boot\n\nSetup and usage in Spring Boot 3 is demonstrated https:\u002F\u002Fgithub.com\u002Fresilience4j\u002Fresilience4j-spring-boot3-demo[here].\n\nVirtual thread support (Java 21 Project Loom)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nStarting with Resilience4j 3 you can switch the internal schedulers to Java *virtual threads*.\n\n[source,yaml]\n----\nresilience4j:\n  thread:\n    type: virtual\n----\n\nThe same can also be enabled via JVM argument:\n\n```\n-Dresilience4j.thread.type=virtual\n```\n\nIf the property (or system property) is omitted the library falls back to regular *platform* threads.\n\n== Usage examples\n\n[[circuitbreaker-retry-fallback]]\n=== CircuitBreaker, Retry and Fallback\n\nThe following example shows how to decorate a lambda expression (Supplier) with a CircuitBreaker and how to retry the call at most 3 times when an exception occurs.\nYou can configure the wait interval between retries and also configure a custom backoff algorithm.\n\nThe example uses Vavr's Try Monad to recover from an exception and invoke another lambda expression as a fallback, when even all retries have failed.\n\n[source,java]\n----\n\u002F\u002F Simulates a Backend Service\npublic interface BackendService {\n    String doSomething();\n}\n\n\u002F\u002F Create a CircuitBreaker (use default configuration)\nCircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults(\"backendName\");\n\u002F\u002F Create a Retry with at most 3 retries and a fixed time interval between retries of 500ms\nRetry retry = Retry.ofDefaults(\"backendName\");\n\n\u002F\u002F Decorate your call to BackendService.doSomething() with a CircuitBreaker\nSupplier\u003CString> decoratedSupplier = CircuitBreaker\n    .decorateSupplier(circuitBreaker, backendService::doSomething);\n\n\u002F\u002F Decorate your call with automatic retry\ndecoratedSupplier = Retry\n    .decorateSupplier(retry, decoratedSupplier);\n\n\u002F\u002F Use of Vavr's Try to\n\u002F\u002F execute the decorated supplier and recover from any exception\nString result = Try.ofSupplier(decoratedSupplier)\n    .recover(throwable -> \"Hello from Recovery\").get();\n\n\u002F\u002F When you don't want to decorate your lambda expression,\n\u002F\u002F but just execute it and protect the call by a CircuitBreaker.\nString result = circuitBreaker.executeSupplier(backendService::doSomething);\n----\n\n==== CircuitBreaker and RxJava2\n\nThe following example shows how to decorate an Observable by using the custom RxJava operator.\n\n[source,java]\n----\nCircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults(\"testName\");\nObservable.fromCallable(backendService::doSomething)\n    .compose(CircuitBreakerOperator.of(circuitBreaker))\n----\n\nNOTE: Resilience4j also provides RxJava operators for `+RateLimiter+`, `+Bulkhead+`, `+TimeLimiter+` and `+Retry+`.\nFind out more in our *https:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Fgetting-started-2[User Guide]*.\n\n==== CircuitBreaker and Spring Reactor\n\nThe following example shows how to decorate a Mono by using the custom Reactor operator.\n\n[source,java]\n----\nCircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults(\"testName\");\nMono.fromCallable(backendService::doSomething)\n    .transformDeferred(CircuitBreakerOperator.of(circuitBreaker))\n----\n\nNOTE: Resilience4j also provides Reactor operators for `+RateLimiter+`, `+Bulkhead+`, `+TimeLimiter+` and `+Retry+`.\nFind out more in our *https:\u002F\u002Fresilience4j.readme.io\u002Fdocs\u002Fgetting-started-1[User Guide]*.\n\n[[ratelimiter]]\n=== RateLimiter\n\nThe following example shows how to restrict the calling rate of some method to be not higher than 1 request\u002Fsecond.\n\n[source,java]\n----\n\u002F\u002F Create a custom RateLimiter configuration\nRateLimiterConfig config = RateLimiterConfig.custom()\n    .timeoutDuration(Duration.ofMillis(100))\n    .limitRefreshPeriod(Duration.ofSeconds(1))\n    .limitForPeriod(1)\n    .build();\n\u002F\u002F Create a RateLimiter\nRateLimiter rateLimiter = RateLimiter.of(\"backendName\", config);\n\n\u002F\u002F Decorate your call to BackendService.doSomething()\nSupplier\u003CString> restrictedSupplier = RateLimiter\n    .decorateSupplier(rateLimiter, backendService::doSomething);\n\n\u002F\u002F First call is successful\nTry\u003CString> firstTry = Try.ofSupplier(restrictedSupplier);\nassertThat(firstTry.isSuccess()).isTrue();\n\n\u002F\u002F Second call fails, because the call was not permitted\nTry\u003CString> secondTry = Try.of(restrictedSupplier);\nassertThat(secondTry.isFailure()).isTrue();\nassertThat(secondTry.getCause()).isInstanceOf(RequestNotPermitted.class);\n----\n\n[[bulkhead]]\n=== Bulkhead\nThere are two isolation strategies and bulkhead implementations.\n\n==== SemaphoreBulkhead\nThe following example shows how to decorate a lambda expression with a Bulkhead.\nA Bulkhead can be used to limit the amount of parallel executions.\nThis bulkhead abstraction should work well across a variety of threading and io models.\nIt is based on a semaphore, and unlike Hystrix, does not provide \"shadow\" thread pool option.\n\n[source,java]\n----\n\u002F\u002F Create a custom Bulkhead configuration\nBulkheadConfig config = BulkheadConfig.custom()\n    .maxConcurrentCalls(150)\n    .maxWaitDuration(100)\n    .build();\n\nBulkhead bulkhead = Bulkhead.of(\"backendName\", config);\n\nSupplier\u003CString> supplier = Bulkhead\n    .decorateSupplier(bulkhead, backendService::doSomething);\n----\n\n[[threadpoolbulkhead]]\n==== ThreadPoolBulkhead\nThe following example shows how to use a lambda expression with a ThreadPoolBulkhead which uses a bounded queue and a fixed thread pool.\n\n[source,java]\n----\n\u002F\u002F Create a custom ThreadPoolBulkhead configuration\nThreadPoolBulkheadConfig config = ThreadPoolBulkheadConfig.custom()\n    .maxThreadPoolSize(10)\n    .coreThreadPoolSize(2)\n    .queueCapacity(20)\n    .build();\n\nThreadPoolBulkhead bulkhead = ThreadPoolBulkhead.of(\"backendName\", config);\n\n\u002F\u002F Decorate or execute immediately a lambda expression with a ThreadPoolBulkhead.\nSupplier\u003CCompletionStage\u003CString>> supplier = ThreadPoolBulkhead\n    .decorateSupplier(bulkhead, backendService::doSomething);\n\nCompletionStage\u003CString> execution = bulkhead\n    .executeSupplier(backendService::doSomething);\n----\n\n[[events]]\n== Consume emitted events\n\n`+CircuitBreaker+`, `+RateLimiter+`, `+Cache+`, `+Bulkhead+`, `+TimeLimiter+` and `+Retry+` components emit a stream of events.\nIt can be consumed for logging, assertions and any other purpose.\n\n=== Examples\n\nA `+CircuitBreakerEvent+` can be a state transition, a circuit breaker reset, a successful call, a recorded error or an ignored error.\nAll events contains additional information like event creation time and processing duration of the call.\nIf you want to consume events, you have to register an event consumer.\n\n[source,java]\n----\ncircuitBreaker.getEventPublisher()\n    .onSuccess(event -> logger.info(...))\n    .onError(event -> logger.info(...))\n    .onIgnoredError(event -> logger.info(...))\n    .onReset(event -> logger.info(...))\n    .onStateTransition(event -> logger.info(...));\n\u002F\u002F Or if you want to register a consumer listening to all events, you can do:\ncircuitBreaker.getEventPublisher()\n    .onEvent(event -> logger.info(...));\n----\n\nYou can use RxJava or Spring Reactor Adapters to convert the `+EventPublisher+` into a Reactive Stream.\nThe advantage of a Reactive Stream is that you can use RxJava's `+observeOn+` operator to specify a different Scheduler that the CircuitBreaker will use to send notifications to its observers\u002Fconsumers.\n\n[source,java]\n----\nRxJava2Adapter.toFlowable(circuitBreaker.getEventPublisher())\n    .filter(event -> event.getEventType() == Type.ERROR)\n    .cast(CircuitBreakerOnErrorEvent.class)\n    .subscribe(event -> logger.info(...))\n----\n\nNOTE: You can also consume events from other components.\nFind out more in our *https:\u002F\u002Fresilience4j.readme.io\u002F[User Guide]*.\n\n== Talks\n\n[cols=\"4*\"]\n|===\n\n|0:34\n|https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=kR2sm1zelI4[Battle of the Circuit Breakers: Resilience4J vs Istio]\n|Nicolas Frankel\n|GOTO Berlin\n\n|0:33\n|https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=AwcjOhD91Q0[Battle of the Circuit Breakers: Istio vs. Hystrix\u002FResilience4J]\n|Nicolas Frankel\n|JFuture\n\n|0:42\n|https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=KosSsZEqS-k&t=157[Resilience patterns in the post-Hystrix world]\n|Tomasz Skowroński\n|Cloud Native Warsaw\n\n|0:52\n|https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=NHVxrLb3jFI[Building Robust and Resilient Apps Using Spring Boot and Resilience4j]\n|David Caron\n|SpringOne\n\n|0:22\n|https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=gvDvOWtPLVY&t=140[Hystrix is dead, now what?]\n|Tomasz Skowroński\n|DevoxxPL\n\n|===\n\n== Companies that use Resilience4j\n\n* *Deutsche Telekom* (In an application with over 400 million requests per day)\n* *AOL* (In an application with low latency requirements)\n* *Netpulse* (In a system with 40+ integrations)\n* *wescale.de* (In a B2B integration platform)\n* *Topia* (In an HR application built with microservices architecture)\n* *Auto Trader Group plc* (The largest Britain digital automotive marketplace)\n* *PlayStation Network* (A platform backend)\n* *TUI InfoTec GmbH* (Backend applications inside of reservation booking workflow streams for accommodations)\n\n== License\n\nCopyright 2020 Robert Winkler, Bohdan Storozhuk, Mahmoud Romeh, Dan Maas and others\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http:\u002F\u002Fwww.apache.org\u002Flicenses\u002FLICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and limitations under the License.\n","Resilience4j 是一个专为 Java 8 和函数式编程设计的轻量级容错库。它通过提供高阶函数（装饰器）来增强任何函数接口、lambda 表达式或方法引用，支持断路器、限流器、重试和隔离舱等核心功能。用户可以根据需要选择并堆叠多个装饰器，以实现灵活的容错策略。该库适用于微服务架构中，帮助开发者构建更加健壮和可靠的服务，特别是在面对网络不稳定、服务超载等常见问题时。","2026-06-11 02:58:25","top_language"]