Учитывая, что Hystrix переходит в режим обслуживания, я работаю над переносом (довольно большой) кодовой базы в Resilience4j.
Я активно использую следующий шаблон с Hystrix:
new HystrixCommand<SomeReturnValue>(DependencyKeys.DEPENDENCY) {
@Override
protected SomeReturnValue run() {
return someExpensiveCall();
}
}
.observe()
И я хочу повторить некоторые функции Hystrix с Resilience4j.
Пока у меня есть следующий синтаксис для подключения внешнего вызова:
resilience.single(DependencyKeys.DEPENDENCY, this::someExpensiveCall);
Где класс Resilience
предоставляет метод single
:
public <T> Single<T> single(ResilienceKey key, Callable<T> callable) {
return Completable.complete()
.subscribeOn(Schedulers.computation())
.observeOn(configuration.scheduler(key))
.andThen(Single.defer(() -> Single.fromCallable(callable)
.lift(CircuitBreakerOperator.of(configuration.circuitBreaker(key)))
.lift(RateLimiterOperator.of(configuration.rateLimiter(key)))
.lift(BulkheadOperator.of(configuration.bulkhead(key)))
))
.observeOn(Schedulers.computation());
}
Как это может выглядеть, чтобы лучше напоминать то, что вы получаете с Hystrix, с точки зрения разрыва схемы и запуска кода в разных пулах потоков, но более разумным способом. Мне действительно не нравится начинать цепочку с Completable.complete()
, просто чтобы заставить observeOn
до того, как будет вызван фактический вызываемый объект.