Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
resilience4j — Библиотека отказоустойчивости для Java, предоставляющая circuit breaker, rate limiter, retry, bulkhead, timeout и декораторы кэша для функционального программирования. | Kitploit
Инструменты/GitHubGitHub/resilience4j/resilience4j
Утилиты общего назначенияУтилиты и фреймворки
GitHubresilience4j/resilience4j

resilience4j

Библиотека отказоустойчивости для Java, предоставляющая circuit breaker, rate limiter, retry, bulkhead, timeout и декораторы кэша для функционального программирования.

Репозиторий
10.7k1.5k1 месяц назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

= Библиотека отказоустойчивости, предназначенная для функционального программирования :author: Robert Winkler and Bohdan Storozhuk :icons: :toc: macro :numbered: 1 ifdef::env-github[] :tip-caption: 💡 :note-caption: ℹ️ :important-caption: ❗ :caution-caption: 🔥 :warning-caption: ⚠️ endif::[]

image:https://github.com/resilience4j/resilience4j/actions/workflows/gradle-build.yml/badge.svg["Build Status"] image:https://img.shields.io/nexus/r/io.github.resilience4j/resilience4j-circuitbreaker?server=https%3A%2F%2Foss.sonatype.org["Release"] image:https://img.shields.io/nexus/s/io.github.resilience4j/resilience4j-circuitbreaker?server=https%3A%2F%2Foss.sonatype.org["Snapshot"] image:http://img.shields.io/badge/license-ASF2-blue.svg["Apache License 2", link="http://www.apache.org/licenses/LICENSE-2.0.txt"]

image:https://sonarcloud.io/api/project_badges/measure?project=resilience4j_resilience4j&metric=coverage["Coverage", link="https://sonarcloud.io/dashboard?id=resilience4j_resilience4j"] image:https://sonarcloud.io/api/project_badges/measure?project=resilience4j_resilience4j&metric=sqale_rating["Maintainability", link="https://sonarcloud.io/dashboard?id=resilience4j_resilience4j"] image:https://sonarcloud.io/api/project_badges/measure?project=resilience4j_resilience4j&metric=reliability_rating["Reliability", link="https://sonarcloud.io/dashboard?id=resilience4j_resilience4j"] image:https://sonarcloud.io/api/project_badges/measure?project=resilience4j_resilience4j&metric=security_rating["Security", link="https://sonarcloud.io/dashboard?id=resilience4j_resilience4j"] image:https://sonarcloud.io/api/project_badges/measure?project=resilience4j_resilience4j&metric=vulnerabilities["Vulnerabilities", link="https://sonarcloud.io/dashboard?id=resilience4j_resilience4j"] image:https://sonarcloud.io/api/project_badges/measure?project=resilience4j_resilience4j&metric=bugs["Bugs", link="https://sonarcloud.io/dashboard?id=resilience4j_resilience4j"]

image:https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg["SWUbanner",link="https://vshymanskyy.github.io/StandWithUkraine"]

toc::[]

== Введение

Resilience4j — это легковесная библиотека для обеспечения отказоустойчивости, предназначенная для функционального программирования. Resilience4j предоставляет функции высшего порядка (декораторы) для расширения любого функционального интерфейса, лямбда-выражения или ссылки на метод с помощью Circuit Breaker, Rate Limiter, Retry или Bulkhead. Вы можете накладывать несколько декораторов на любой функциональный интерфейс, лямбда-выражение или ссылку на метод. Преимущество в том, что вы можете выбрать только те декораторы, которые вам нужны, и ничего больше.

Resilience4j 3 требует Java 21.

[source,java]

// Create a CircuitBreaker with default configuration CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("backendService");

// Create a Retry with default configuration // 3 retry attempts and a fixed time interval between retries of 500ms Retry retry = Retry.ofDefaults("backendService");

// Create a Bulkhead with default configuration Bulkhead bulkhead = Bulkhead.ofDefaults("backendService");

Supplier supplier = () -> backendService .doSomething(param1, param2);

// Decorate your call to backendService.doSomething() // with a Bulkhead, CircuitBreaker and Retry // **note: you will need the resilience4j-all dependency for this Supplier decoratedSupplier = Decorators.ofSupplier(supplier) .withCircuitBreaker(circuitBreaker) .withBulkhead(bulkhead) .withRetry(retry) .decorate();

// Execute the decorated supplier and recover from any exception String result = Try.ofSupplier(decoratedSupplier) .recover(throwable -> "Hello from Recovery").get();

// When you don't want to decorate your lambda expression, // but just execute it and protect the call by a CircuitBreaker. String result = circuitBreaker .executeSupplier(backendService::doSomething);

// You can also run the supplier asynchronously in a ThreadPoolBulkhead ThreadPoolBulkhead threadPoolBulkhead = ThreadPoolBulkhead .ofDefaults("backendService");

// The Scheduler is needed to schedule a timeout on a non-blocking CompletableFuture ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3); TimeLimiter timeLimiter = TimeLimiter.of(Duration.ofSeconds(1));

CompletableFuture future = Decorators.ofSupplier(supplier) .withThreadPoolBulkhead(threadPoolBulkhead) .withTimeLimiter(timeLimiter, scheduler) .withCircuitBreaker(circuitBreaker) .withFallback(asList(TimeoutException.class, CallNotPermittedException.class, BulkheadFullException.class), throwable -> "Hello from Recovery") .get().toCompletableFuture();

NOTE: С Resilience4j вам не нужно действовать по принципу «всё или ничего» — вы можете https://mvnrepository.com/artifact/io.github.resilience4j[*выбрать то, что нужно*].

== Документация

Настройка и использование описаны в нашем https://resilience4j.readme.io/docs[Руководстве пользователя].

  • https://github.com/resilience4j-docs-ja/resilience4j-docs-ja[Неофициальный перевод на японский язык волонтёрами]

  • https://github.com/lmhmhl/Resilience4j-Guides-Chinese[Неофициальный перевод документации Resilience4j на китайский язык волонтёрами]

== Обзор

Resilience4j предоставляет несколько основных модулей:

  • resilience4j-circuitbreaker: Размыкание цепи
  • resilience4j-ratelimiter: Ограничение частоты запросов
  • resilience4j-bulkhead: Изоляция ресурсов
  • resilience4j-retry: Автоматические повторные попытки (синхронные и асинхронные)
  • resilience4j-timelimiter: Обработка тайм-аутов
  • resilience4j-cache: Кэширование результатов

Существуют также дополнительные модули для метрик, Feign, Kotlin, Spring, Ratpack, Vertx, RxJava2 и других.

NOTE: Полный список модулей приведён в нашем https://resilience4j.readme.io/docs#section-modularization[Руководстве пользователя].

TIP: Пакет основных модулей или билдер +Decorators+ см. в https://mvnrepository.com/artifact/io.github.resilience4j/resilience4j-all[resilience4j-all].

== Лучшие практики

=== Управление экземплярами: когда совместно использовать, а когда нет

Одно из самых важных понятий для новичков — понимать, когда создавать отдельные экземпляры, а когда совместно использовать экземпляры для разных удалённых сервисов или бэкендов.

[IMPORTANT]

Золотое правило: создавайте уникальный экземпляр (с уникальным идентификатором) для каждого защищаемого удалённого сервиса или бэкенда, с которым вы взаимодействуете.

==== Почему важны уникальные экземпляры

Создание отдельных экземпляров для каждого бэкенд-сервиса критически важно для:

  1. Правильного сбора метрик — каждый экземпляр отслеживает собственные метрики, что позволяет контролировать состояние отдельных сервисов
  2. Изоляции сбоев — если Сервис A выйдет из строя, это не повлияет на паттерны отказоустойчивости, защищающие Сервис B
  3. Независимой конфигурации — для разных бэкендов могут требоваться разные пороговые значения circuit breaker, ограничения параллелизма, лимиты частоты запросов или политики повторных попыток

==== Паттерны, зависящие от экземпляра, и паттерны, не зависящие от экземпляра

===== Паттерны, зависящие от экземпляра (НЕЛЬЗЯ совместно использовать)

Эти паттерны хранят состояние, специфичное для конкретного сервиса, и ДОЛЖНЫ иметь отдельные экземпляры:

  • CircuitBreaker — отслеживает частоту сбоев и состояние (OPEN/CLOSED/HALF_OPEN) для каждого сервиса

[source,java]

// CORRECT: Separate CircuitBreaker for each service CircuitBreaker paymentServiceCB = CircuitBreaker.ofDefaults("paymentService"); CircuitBreaker inventoryServiceCB = CircuitBreaker.ofDefaults("inventoryService"); CircuitBreaker notificationServiceCB = CircuitBreaker.ofDefaults("notificationService");

// WRONG: Sharing one CircuitBreaker across multiple services CircuitBreaker sharedCB = CircuitBreaker.ofDefaults("shared"); // DON'T DO THIS! // If one service fails, the circuit opens for ALL services!

  • Bulkhead (и SemaphoreBulkhead, и ThreadPoolBulkhead) — управляет лимитами параллельных вызовов для каждого сервиса

[source,java]

// CORRECT: Separate Bulkhead for each service Bulkhead paymentBulkhead = Bulkhead.ofDefaults("paymentService"); Bulkhead inventoryBulkhead = Bulkhead.ofDefaults("inventoryService");

// WRONG: Sharing limits resource isolation benefits Bulkhead sharedBulkhead = Bulkhead.ofDefaults("shared"); // DON'T DO THIS!

  • RateLimiter — контролирует частоту запросов для каждого сервиса

[source,java]

// CORRECT: Different rate limits for different services RateLimiter apiRateLimiter = RateLimiter.ofDefaults("externalAPI"); RateLimiter dbRateLimiter = RateLimiter.ofDefaults("database");

===== Паттерны, не зависящие от экземпляра (можно совместно использовать, но лучше не стоит)

Эти паттерны создают новый контекст для каждого выполнения и не хранят состояние, специфичное для сервиса:

  • Retry — конфигурацию можно совместно использовать, но для корректных метрик всё равно рекомендуются уникальные экземпляры
  • TimeLimiter — настройки тайм-аута можно совместно использовать, если они одинаковы для всех сервисов

[source,java]

// TECHNICALLY OK: Retry doesn't maintain state between calls Retry sharedRetry = Retry.ofDefaults("shared");

// BETTER: Unique instances provide better metrics and monitoring Retry paymentRetry = Retry.ofDefaults("paymentService"); Retry inventoryRetry = Retry.ofDefaults("inventoryService");

// Now you can track: // - How many retry attempts failed for paymentService specifically // - How many retry attempts failed for inventoryService specifically

==== Рекомендуемый подход: всегда используйте уникальные экземпляры

Даже для паттернов, которые можно совместно использовать, рекомендуется создавать уникальные экземпляры, потому что:

  • Лучшая наблюдаемость — метрики помечаются именем экземпляра, что позволяет видеть, какой бэкенд испытывает проблемы
  • Более простая диагностика — чёткое разделение упрощает отладку проблем в продакшене
  • Гибкость на будущее — если позже вам понадобятся разные конфигурации для каждого сервиса, экземпляры уже будут разделены

===== Полный пример: несколько сервисов

[source,java]

// You have 3 backend services to protect public class ServiceOrchestrator {

root@kitploit:~
// Payment Service protection
private final CircuitBreaker paymentCB = CircuitBreaker.ofDefaults("paymentService");
private final Retry paymentRetry = Retry.ofDefaults("paymentService");
private final Bulkhead paymentBulkhead = Bulkhead.ofDefaults("paymentService");

// Inventory Service protection
private final CircuitBreaker inventoryCB = CircuitBreaker.ofDefaults("inventoryService");
private final Retry inventoryRetry = Retry.ofDefaults("inventoryService");
private final Bulkhead inventoryBulkhead = Bulkhead.ofDefaults("inventoryService");

// Notification Service protection
private final CircuitBreaker notificationCB = CircuitBreaker.ofDefaults("notificationService");
private final Retry notificationRetry = Retry.ofDefaults("notificationService");

public Order processOrder(OrderRequest request) {
    // Each service call is protected by its own set of resilience instances

    // Call payment service
    Supplier<PaymentResult> paymentCall = () -> paymentService.charge(request);
    PaymentResult payment = Decorators.ofSupplier(paymentCall)
        .withCircuitBreaker(paymentCB)
        .withRetry(paymentRetry)
        .withBulkhead(paymentBulkhead)
        .decorate()
        .get();

    // Call inventory service
    Supplier<InventoryResult> inventoryCall = () -> inventoryService.reserve(request);
    InventoryResult inventory = Decorators.ofSupplier(inventoryCall)
        .withCircuitBreaker(inventoryCB)
        .withRetry(inventoryRetry)
        .withBulkhead(inventoryBulkhead)
        .decorate()
        .get();

    // 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)
    Runnable notificationCall = () -> notificationService.send(request);
    Decorators.ofRunnable(notificationCall)
        .withCircuitBreaker(notificationCB)
        .withRetry(notificationRetry)
        .decorate()
        .run();

    return new Order(payment, inventory);
}

}

==== Использование реестров для управления экземплярами

Resilience4j предоставляет классы реестров для эффективного управления несколькими экземплярами:

[source,java]

// Create a registry with custom default configuration CircuitBreakerConfig defaultConfig = CircuitBreakerConfig.custom() .failureRateThreshold(50) .waitDurationInOpenState(Duration.ofSeconds(30)) .build();

CircuitBreakerRegistry registry = CircuitBreakerRegistry.of(defaultConfig);

// Get or create instances by name CircuitBreaker paymentCB = registry.circuitBreaker("paymentService"); CircuitBreaker inventoryCB = registry.circuitBreaker("inventoryService");

// You can also override config for specific instances CircuitBreakerConfig customConfig = CircuitBreakerConfig.custom() .failureRateThreshold(80) // More lenient for this service .build(); CircuitBreaker legacyCB = registry.circuitBreaker("legacyService", customConfig);

NOTE: Реестры особенно полезны в приложениях Spring Boot, где они настраиваются автоматически, а экземпляры создаются по требованию на основе свойств конфигурации.

==== Итоги

[cols="<.<*", options="header"] |=== |Паттерн |Можно ли совместно использовать? |Следует ли совместно использовать? |Почему?

|CircuitBreaker |Нет |Нет |Состояние специфично для сервиса. Совместное использование приводит к тому, что сбои одного сервиса влияют на все остальные.

|Bulkhead |Нет |Нет |Лимиты параллельных вызовов должны быть изолированы для каждого сервиса для корректного управления ресурсами.

|RateLimiter |Нет |Нет |Лимиты частоты запросов обычно различаются для каждого сервиса, и совместное использование сводит на нет их назначение.

|Retry |Да |Нет |Хотя технически безопасно совместно использовать, уникальные экземпляры обеспечивают лучшие метрики и наблюдаемость.

|TimeLimiter |Да |Нет |Хотя технически безопасно совместно использовать, уникальные экземпляры обеспечивают лучшие метрики и наблюдаемость.

|Cache |Зависит |Зависит |Совместно используйте только в том случае, если кэшируемые данные действительно идентичны во всех сценариях использования.

|===

[TIP]

Если сомневаетесь, создавайте отдельные экземпляры. Накладные расходы минимальны, а преимущества для метрик, отладки и гибкости значительны.

== Паттерны отказоустойчивости

[cols="<.<*", options="header"] |=== |название |как это работает? |описание |ссылки

|Retry |повторяет неудачные выполнения |Многие сбои носят временный характер и могут устраниться сами после короткой задержки. |<<circuitbreaker-retry-fallback,обзор>>, https://resilience4j.readme.io/docs/retry[документация], https://resilience4j.readme.io/docs/getting-started-3#annotations[Spring]

|Circuit Breaker |временно блокирует возможные сбои |Когда система серьёзно перегружена, быстрый отказ лучше, чем заставлять клиентов ждать. |<<circuitbreaker-retry-fallback,обзор>>, https://resilience4j.readme.io/docs/circuitbreaker[документация], https://resilience4j.readme.io/docs/feign[Feign], https://resilience4j.readme.io/docs/getting-started-3#annotations[Spring]

|Rate Limiter |ограничивает количество выполнений за период |Ограничьте частоту входящих запросов. |<<ratelimiter,обзор>>, https://resilience4j.readme.io/docs/ratelimiter[документация], https://resilience4j.readme.io/docs/feign[Feign], https://resilience4j.readme.io/docs/getting-started-3#annotations[Spring]

|Time Limiter |ограничивает продолжительность выполнения |После определённого интервала ожидания успешный результат маловероятен. |https://resilience4j.readme.io/docs/timeout[документация], https://resilience4j.readme.io/docs/getting-started-3#annotations[Spring]

|Bulkhead |ограничивает параллельные выполнения |Ресурсы изолируются в пулы, чтобы при сбое одного остальные продолжали работать. |<<bulkhead,обзор>>, https://resilience4j.readme.io/docs/bulkhead[документация], https://resilience4j.readme.io/docs/getting-started-3#annotations[Spring]

|Cache |запоминает успешный результат |Некоторая доля запросов может быть похожей. |https://resilience4j.readme.io/docs/cache[документация]

|Fallback |предоставляет альтернативный результат при сбоях |Сбои всё равно будут — спланируйте, что вы будете делать, когда это произойдёт. |<<circuitbreaker-retry-fallback,Try::recover>>, https://resilience4j.readme.io/docs/getting-started-3#section-annotations[Spring], https://resilience4j.readme.io/docs/feign[Feign]

|===

Приведённая выше таблица основана на https://github.com/App-vNext/Polly#resilience-policies[Polly: политики отказоустойчивости].

NOTE: Чтобы узнать больше о паттернах отказоустойчивости, обратитесь к разделу link:#Talks[Доклады]. Узнайте больше о компонентах в нашем https://resilience4j.readme.io/docs/getting-started-2[Руководстве пользователя].

== Spring Boot

Настройка и использование в Spring Boot 3 продемонстрированы https://github.com/resilience4j/resilience4j-spring-boot3-demo[здесь].

Поддержка виртуальных потоков (Java 21 Project Loom) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Начиная с Resilience4j 3 вы можете переключить внутренние планировщики на Java виртуальные потоки.

[source,yaml]

resilience4j: thread: type: virtual

То же самое можно включить с помощью аргумента JVM:``` -Dresilience4j.thread.type=virtual

root@kitploit:~
Если свойство (или системное свойство) не указано, библиотека возвращается к обычным *платформенным* потокам.

== Примеры использования

[[circuitbreaker-retry-fallback]]
=== CircuitBreaker, Retry и Fallback

В следующем примере показано, как декорировать лямбда-выражение (Supplier) с помощью CircuitBreaker и как повторить вызов не более 3 раз при возникновении исключения.
Вы можете настроить интервал ожидания между повторами, а также настроить собственный алгоритм backoff.

В примере используется монада Try из Vavr, чтобы восстановиться после исключения и вызвать другое лямбда-выражение в качестве запасного варианта (fallback), когда даже все повторы завершились неудачей.

[source,java]
----
// Simulates a Backend Service
public interface BackendService {
    String doSomething();
}

// Create a CircuitBreaker (use default configuration)
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("backendName");
// Create a Retry with at most 3 retries and a fixed time interval between retries of 500ms
Retry retry = Retry.ofDefaults("backendName");

// Decorate your call to BackendService.doSomething() with a CircuitBreaker
Supplier<String> decoratedSupplier = CircuitBreaker
    .decorateSupplier(circuitBreaker, backendService::doSomething);

// Decorate your call with automatic retry
decoratedSupplier = Retry
    .decorateSupplier(retry, decoratedSupplier);

// Use of Vavr's Try to
// execute the decorated supplier and recover from any exception
String result = Try.ofSupplier(decoratedSupplier)
    .recover(throwable -> "Hello from Recovery").get();

// When you don't want to decorate your lambda expression,
// but just execute it and protect the call by a CircuitBreaker.
String result = circuitBreaker.executeSupplier(backendService::doSomething);
----

==== CircuitBreaker и RxJava2

В следующем примере показано, как декорировать Observable с помощью специального оператора RxJava.

[source,java]
----
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName");
Observable.fromCallable(backendService::doSomething)
    .compose(CircuitBreakerOperator.of(circuitBreaker))
----

NOTE: Resilience4j также предоставляет операторы RxJava для `+RateLimiter+`, `+Bulkhead+`, `+TimeLimiter+` и `+Retry+`.
Узнайте больше в нашем *https://resilience4j.readme.io/docs/getting-started-2[Руководстве пользователя]*.

==== CircuitBreaker и Spring Reactor

В следующем примере показано, как декорировать Mono с помощью специального оператора Reactor.

[source,java]
----
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName");
Mono.fromCallable(backendService::doSomething)
    .transformDeferred(CircuitBreakerOperator.of(circuitBreaker))
----

NOTE: Resilience4j также предоставляет операторы Reactor для `+RateLimiter+`, `+Bulkhead+`, `+TimeLimiter+` и `+Retry+`.
Узнайте больше в нашем *https://resilience4j.readme.io/docs/getting-started-1[Руководстве пользователя]*.

[[ratelimiter]]
=== RateLimiter

В следующем примере показано, как ограничить частоту вызовов некоторого метода значением не выше 1 запрос/секунду.

[source,java]
----
// Create a custom RateLimiter configuration
RateLimiterConfig config = RateLimiterConfig.custom()
    .timeoutDuration(Duration.ofMillis(100))
    .limitRefreshPeriod(Duration.ofSeconds(1))
    .limitForPeriod(1)
    .build();
// Create a RateLimiter
RateLimiter rateLimiter = RateLimiter.of("backendName", config);

// Decorate your call to BackendService.doSomething()
Supplier<String> restrictedSupplier = RateLimiter
    .decorateSupplier(rateLimiter, backendService::doSomething);

// First call is successful
Try<String> firstTry = Try.ofSupplier(restrictedSupplier);
assertThat(firstTry.isSuccess()).isTrue();

// Second call fails, because the call was not permitted
Try<String> secondTry = Try.of(restrictedSupplier);
assertThat(secondTry.isFailure()).isTrue();
assertThat(secondTry.getCause()).isInstanceOf(RequestNotPermitted.class);
----

[[bulkhead]]
=== Bulkhead
Существуют две стратегии изоляции и две реализации bulkhead.

==== SemaphoreBulkhead
В следующем примере показано, как декорировать лямбда-выражение с помощью Bulkhead.
Bulkhead можно использовать для ограничения количества параллельных выполнений.
Эта абстракция bulkhead должна хорошо работать в различных моделях потоков и ввода-вывода.
Она основана на семафоре и, в отличие от Hystrix, не предоставляет опцию "теневого" пула потоков.

[source,java]
----
// Create a custom Bulkhead configuration
BulkheadConfig config = BulkheadConfig.custom()
    .maxConcurrentCalls(150)
    .maxWaitDuration(100)
    .build();

Bulkhead bulkhead = Bulkhead.of("backendName", config);

Supplier<String> supplier = Bulkhead
    .decorateSupplier(bulkhead, backendService::doSomething);
----

[[threadpoolbulkhead]]
==== ThreadPoolBulkhead
В следующем примере показано, как использовать лямбда-выражение с ThreadPoolBulkhead, который использует ограниченную очередь и фиксированный пул потоков.

[source,java]
----
// Create a custom ThreadPoolBulkhead configuration
ThreadPoolBulkheadConfig config = ThreadPoolBulkheadConfig.custom()
    .maxThreadPoolSize(10)
    .coreThreadPoolSize(2)
    .queueCapacity(20)
    .build();

ThreadPoolBulkhead bulkhead = ThreadPoolBulkhead.of("backendName", config);

// Decorate or execute immediately a lambda expression with a ThreadPoolBulkhead.
Supplier<CompletionStage<String>> supplier = ThreadPoolBulkhead
    .decorateSupplier(bulkhead, backendService::doSomething);

CompletionStage<String> execution = bulkhead
    .executeSupplier(backendService::doSomething);
----

[[events]]
== Потребление испускаемых событий

Компоненты `+CircuitBreaker+`, `+RateLimiter+`, `+Cache+`, `+Bulkhead+`, `+TimeLimiter+` и `+Retry+` испускают поток событий.
Их можно потреблять для логирования, проверок и любых других целей.

=== Примеры

`+CircuitBreakerEvent+` может быть переходом состояния, сбросом circuit breaker, успешным вызовом, зарегистрированной ошибкой или проигнорированной ошибкой.
Все события содержат дополнительную информацию, например, время создания события и продолжительность обработки вызова.
Если вы хотите потреблять события, вам необходимо зарегистрировать потребителя событий.

[source,java]
----
circuitBreaker.getEventPublisher()
    .onSuccess(event -> logger.info(...))
    .onError(event -> logger.info(...))
    .onIgnoredError(event -> logger.info(...))
    .onReset(event -> logger.info(...))
    .onStateTransition(event -> logger.info(...));
// Or if you want to register a consumer listening to all events, you can do:
circuitBreaker.getEventPublisher()
    .onEvent(event -> logger.info(...));
----

Вы можете использовать адаптеры RxJava или Spring Reactor, чтобы преобразовать `+EventPublisher+` в Reactive Stream.
Преимущество Reactive Stream в том, что вы можете использовать оператор `+observeOn+` из RxJava, чтобы указать другой Scheduler, который CircuitBreaker будет использовать для отправки уведомлений своим наблюдателям/потребителям.

[source,java]
----
RxJava2Adapter.toFlowable(circuitBreaker.getEventPublisher())
    .filter(event -> event.getEventType() == Type.ERROR)
    .cast(CircuitBreakerOnErrorEvent.class)
    .subscribe(event -> logger.info(...))
----

NOTE: Вы также можете потреблять события из других компонентов.
Узнайте больше в нашем *https://resilience4j.readme.io/[Руководстве пользователя]*.

== Доклады

[cols="4*"]
|===

|0:34
|https://www.youtube.com/watch?v=kR2sm1zelI4[Битва circuit breaker'ов: Resilience4J против Istio]
|Nicolas Frankel
|GOTO Berlin

|0:33
|https://www.youtube.com/watch?v=AwcjOhD91Q0[Битва circuit breaker'ов: Istio против Hystrix/Resilience4J]
|Nicolas Frankel
|JFuture

|0:42
|https://www.youtube.com/watch?v=KosSsZEqS-k&t=157[Паттерны отказоустойчивости в мире после Hystrix]
|Tomasz Skowroński
|Cloud Native Warsaw

|0:52
|https://www.youtube.com/watch?v=NHVxrLb3jFI[Создание надёжных и отказоустойчивых приложений с помощью Spring Boot и Resilience4j]
|David Caron
|SpringOne

|0:22
|https://www.youtube.com/watch?v=gvDvOWtPLVY&t=140[Hystrix мёртв, что дальше?]
|Tomasz Skowroński
|DevoxxPL

|===

== Компании, использующие Resilience4j

* *Deutsche Telekom* (в приложении с более чем 400 миллионами запросов в день)
* *AOL* (в приложении с требованиями низкой задержки)
* *Netpulse* (в системе с 40+ интеграциями)
* *wescale.de* (в интеграционной платформе B2B)
* *Topia* (в HR-приложении, построенном на архитектуре микросервисов)
* *Auto Trader Group plc* (крупнейшая британская цифровая автомобильная торговая площадка)
* *PlayStation Network* (бэкенд платформы)
* *TUI InfoTec GmbH* (бэкенд-приложения в потоках процессов бронирования мест размещения)

== Лицензия

Авторские права 2020 Robert Winkler, Bohdan Storozhuk, Mahmoud Romeh, Dan Maas и другие

Лицензировано в соответствии с Apache License, версия 2.0 ("Лицензия");
вы не можете использовать этот файл иначе как в соответствии с Лицензией.
Вы можете получить копию Лицензии по адресу:

    http://www.apache.org/licenses/LICENSE-2.0

Если иное не требуется применимым законодательством или не согласовано в письменной форме, программное обеспечение, распространяемое в соответствии с Лицензией, распространяется на основе "AS IS",
БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ ИЛИ УСЛОВИЙ, явных или подразумеваемых.
См. Лицензию для получения информации о конкретных разрешениях и ограничениях.
Скачать инструмент