use of io.github.resilience4j.circuitbreaker.CircuitBreakerOpenException in project resilience4j by resilience4j.
the class CircuitBreakerTransformer method apply.
@Override
public Upstream<T> apply(Upstream<? extends T> upstream) throws Exception {
return down -> {
long start;
if (circuitBreaker.isCallPermitted()) {
start = System.nanoTime();
upstream.connect(new Downstream<T>() {
@Override
public void success(T value) {
long durationInNanos = System.nanoTime() - start;
circuitBreaker.onSuccess(durationInNanos);
down.success(value);
}
@Override
public void error(Throwable throwable) {
long durationInNanos = System.nanoTime() - start;
circuitBreaker.onError(durationInNanos, throwable);
try {
if (recoverer != null) {
down.success(recoverer.apply(throwable));
} else {
down.error(throwable);
}
} catch (Throwable t) {
down.error(t);
}
}
@Override
public void complete() {
down.complete();
}
});
} else {
Throwable t = new CircuitBreakerOpenException(String.format("CircuitBreaker '%s' is open", circuitBreaker.getName()));
if (recoverer != null) {
try {
down.success(recoverer.apply(t));
} catch (Throwable t2) {
down.error(t2);
}
} else {
down.error(t);
}
}
};
}
use of io.github.resilience4j.circuitbreaker.CircuitBreakerOpenException in project resilience4j by resilience4j.
the class CircuitBreakerExportsTest method testExportsCircuitBreakerMetrics.
@Test
public void testExportsCircuitBreakerMetrics() {
// Given
final CollectorRegistry registry = new CollectorRegistry();
final CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("foo");
CircuitBreakerExports.ofIterable("boo_circuit_breaker", singletonList(circuitBreaker)).register(registry);
final Supplier<Map<String, Double>> values = () -> HashSet.of("successful", "failed", "not_permitted", "buffered", "buffered_max").map(callType -> Tuple.of(callType, registry.getSampleValue("boo_circuit_breaker_calls", new String[] { "name", "call_result" }, new String[] { "foo", callType }))).toMap(t -> t);
// When
final Map<String, Double> initialValues = values.get();
circuitBreaker.executeRunnable(() -> {
});
final Map<String, Double> afterSuccessValues = values.get();
try {
circuitBreaker.executeRunnable(() -> {
throw new SomeAppException("Some exception");
});
} catch (RuntimeException e) {
// expected
}
final Map<String, Double> afterFailureValues = values.get();
circuitBreaker.transitionToOpenState();
try {
circuitBreaker.executeRunnable(() -> {
});
} catch (CircuitBreakerOpenException e) {
// expected
}
final Map<String, Double> afterDeclinedValues = values.get();
// Then
assertThat(initialValues).isEqualTo(HashMap.of("successful", 0.0, "failed", 0.0, "not_permitted", 0.0, "buffered", 0.0, "buffered_max", 100.0));
assertThat(afterSuccessValues).isEqualTo(HashMap.of("successful", 1.0, "failed", 0.0, "not_permitted", 0.0, "buffered", 1.0, "buffered_max", 100.0));
assertThat(afterFailureValues).isEqualTo(HashMap.of("successful", 1.0, "failed", 1.0, "not_permitted", 0.0, "buffered", 2.0, "buffered_max", 100.0));
assertThat(afterDeclinedValues).isEqualTo(HashMap.of("successful", 1.0, "failed", 1.0, "not_permitted", 1.0, "buffered", 2.0, "buffered_max", 100.0));
}
use of io.github.resilience4j.circuitbreaker.CircuitBreakerOpenException in project resilience4j by resilience4j.
the class CircuitBreakerMethodInterceptor method invoke.
@SuppressWarnings("unchecked")
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
CircuitBreaker annotation = invocation.getMethod().getAnnotation(CircuitBreaker.class);
RecoveryFunction<?> recoveryFunction = annotation.recovery().newInstance();
if (registry == null) {
registry = CircuitBreakerRegistry.ofDefaults();
}
io.github.resilience4j.circuitbreaker.CircuitBreaker breaker = registry.circuitBreaker(annotation.name());
if (breaker == null) {
return invocation.proceed();
}
Class<?> returnType = invocation.getMethod().getReturnType();
if (Promise.class.isAssignableFrom(returnType)) {
Promise<?> result = (Promise<?>) proceed(invocation, breaker, recoveryFunction);
if (result != null) {
CircuitBreakerTransformer transformer = CircuitBreakerTransformer.of(breaker).recover(recoveryFunction);
result = result.transform(transformer);
}
return result;
} else if (Observable.class.isAssignableFrom(returnType)) {
Observable<?> result = (Observable<?>) proceed(invocation, breaker, recoveryFunction);
if (result != null) {
CircuitBreakerOperator operator = CircuitBreakerOperator.of(breaker);
result = result.lift(operator).onErrorReturn(t -> recoveryFunction.apply((Throwable) t));
}
return result;
} else if (Flowable.class.isAssignableFrom(returnType)) {
Flowable<?> result = (Flowable<?>) proceed(invocation, breaker, recoveryFunction);
if (result != null) {
CircuitBreakerOperator operator = CircuitBreakerOperator.of(breaker);
result = result.lift(operator).onErrorReturn(t -> recoveryFunction.apply((Throwable) t));
}
return result;
} else if (Single.class.isAssignableFrom(returnType)) {
Single<?> result = (Single<?>) proceed(invocation, breaker, recoveryFunction);
if (result != null) {
CircuitBreakerOperator operator = CircuitBreakerOperator.of(breaker);
result = result.lift(operator).onErrorReturn(t -> recoveryFunction.apply((Throwable) t));
}
return result;
} else if (CompletionStage.class.isAssignableFrom(returnType)) {
final CompletableFuture promise = new CompletableFuture<>();
if (breaker.isCallPermitted()) {
CompletionStage<?> result = (CompletionStage<?>) proceed(invocation, breaker, recoveryFunction);
if (result != null) {
long start = System.nanoTime();
result.whenComplete((v, t) -> {
long durationInNanos = System.nanoTime() - start;
if (t != null) {
breaker.onError(durationInNanos, t);
try {
promise.complete(recoveryFunction.apply((Throwable) t));
} catch (Exception e) {
promise.completeExceptionally(e);
}
} else {
breaker.onSuccess(durationInNanos);
promise.complete(v);
}
});
}
} else {
Throwable t = new CircuitBreakerOpenException(String.format("CircuitBreaker '%s' is open", breaker.getName()));
try {
promise.complete(recoveryFunction.apply((Throwable) t));
} catch (Throwable t2) {
promise.completeExceptionally(t2);
}
}
return promise;
}
return proceed(invocation, breaker, recoveryFunction);
}
use of io.github.resilience4j.circuitbreaker.CircuitBreakerOpenException in project resilience4j by resilience4j.
the class RetrofitCircuitBreaker method decorateCall.
/**
* Decorate {@link Call}s allow {@link CircuitBreaker} functionality.
*
* @param circuitBreaker {@link CircuitBreaker} to apply
* @param call Call to decorate
* @param responseSuccess determines whether the response should be considered an expected response
* @param <T> Response type of call
* @return Original Call decorated with CircuitBreaker
*/
static <T> Call<T> decorateCall(final CircuitBreaker circuitBreaker, final Call<T> call, final Predicate<Response> responseSuccess) {
return new DecoratedCall<T>(call) {
@Override
public void enqueue(final Callback<T> callback) {
try {
CircuitBreakerUtils.isCallPermitted(circuitBreaker);
} catch (CircuitBreakerOpenException cb) {
callback.onFailure(call, cb);
}
final StopWatch stopWatch = StopWatch.start(circuitBreaker.getName());
call.enqueue(new Callback<T>() {
@Override
public void onResponse(final Call<T> call, final Response<T> response) {
if (responseSuccess.test(response)) {
circuitBreaker.onSuccess(stopWatch.stop().getProcessingDuration().toNanos());
} else {
final Throwable throwable = new Throwable("Response error: HTTP " + response.code() + " - " + response.message());
circuitBreaker.onError(stopWatch.stop().getProcessingDuration().toNanos(), throwable);
}
callback.onResponse(call, response);
}
@Override
public void onFailure(final Call<T> call, final Throwable t) {
circuitBreaker.onError(stopWatch.stop().getProcessingDuration().toNanos(), t);
callback.onFailure(call, t);
}
});
}
@Override
public Response<T> execute() throws IOException {
CircuitBreakerUtils.isCallPermitted(circuitBreaker);
final StopWatch stopWatch = StopWatch.start(circuitBreaker.getName());
try {
final Response<T> response = call.execute();
if (responseSuccess.test(response)) {
circuitBreaker.onSuccess(stopWatch.stop().getProcessingDuration().toNanos());
} else {
final Throwable throwable = new Throwable("Response error: HTTP " + response.code() + " - " + response.message());
circuitBreaker.onError(stopWatch.stop().getProcessingDuration().toNanos(), throwable);
}
return response;
} catch (Throwable throwable) {
circuitBreaker.onError(stopWatch.stop().getProcessingDuration().toNanos(), throwable);
throw throwable;
}
}
};
}
use of io.github.resilience4j.circuitbreaker.CircuitBreakerOpenException in project resilience4j by resilience4j.
the class CircuitBreakerSubscriber method onSubscribe.
@Override
public void onSubscribe(Subscription subscription) {
if (SubscriptionHelper.setOnce(this, subscription)) {
if (acquireCallPermit()) {
childSubscriber.onSubscribe(this);
} else {
cancel();
childSubscriber.onSubscribe(this);
childSubscriber.onError(new CircuitBreakerOpenException(String.format("CircuitBreaker '%s' is open", circuitBreaker.getName())));
}
}
}
Aggregations