I have observed that Hystrix treats all exceptions coming out of commands as failures for circuit breaking purposes. It includes exceptions which are thrown from command run () method and created by Hystrix itself, e.g. HystrixTimeoutException.
But I have business exceptions to be thrown from run() method that signify that service responded with valid error which has to be processed further.
One example of such exception is WebServiceFaultException while using WebServiceTemplate from SpringWS.
So I do not need those specific exceptions to trip the circuit.
How this behavior can be achieved?
There is an obvious way of wrapping business exceptions into a holder object, returning it from run() method, then unwrapping it back to the Exception and rethrow. But it was wondering if there is a cleaner way.
There are following solutions available.
Return exception instead of throwing
Most straightforward and dirty approach. This looks a little funky, because you have to erase the command to Object and there is a lot of type casting.
Observable<BusinessResponse> observable = new HystrixCommand<Object>() {
#Override
protected Object run() throws Exception {
try {
return doStuff(...);
} catch (BusinessException e) {
return e; // so Hystrix won't treat it as a failure
}
}
})
.observe()
.flatMap(new Func1<Object, Observable<BusinessResponse>>() {
#Override
public Observable<BusinessResponse> call(Object o) {
if (o instanceof BusinessException) {
return Observable.error((BusinessException)o);
} else {
return Observable.just((BusinessResponse)o);
}
}
});
Use holder object to hold both result and exception
This apporach requires introduction of additional holder class (which can also be used on it's own for other purposes).
class ResultHolder<T, E extends Exception> {
private T result;
private E exception;
public ResultHolder(T result) {
this.result = result;
}
public ResultHolder(E exception) {
if (exception == null) {
throw new IllegalArgumentException("exception can not be null");
}
this.exception = exception;
}
public T get() throws E {
if (exception != null) {
throw exception;
} else {
return result;
}
}
public Observable<T> observe() {
if (exception != null) {
return Observable.error(exception);
} else {
return Observable.just(result);
}
}
#SuppressWarnings("unchecked")
public static <T, E extends Exception> ResultHolder<T, E> wrap(BusinessMethod<T, E> method) {
try {
return new ResultHolder<>(method.call());
} catch (Exception e) {
return new ResultHolder<>((E)e);
}
}
public static <T, E extends Exception> Observable<T> unwrap(ResultHolder<T, E> holder) {
return holder.observe();
}
interface BusinessMethod<T, E extends Exception> {
T call() throws E;
}
}
Now code that uses it looks much cleaner, the only downside might be a fair amount of generics. Also this approach is at it's best in Java 8 where lambdas and method references are available, otherwise it will look clunky.
new HystrixCommand<ResultHolder<BusinessResponse, BusinessException>>() {
#Override
protected ResultHolder<BusinessResponse, BusinessException> run() throws Exception {
return ResultHolder.wrap(() -> doStuff(...));
}
}
.observe()
.flatMap(ResultHolder::unwrap);
Use HystrixBadRequestException
HystrixBadRequestException is a special kind of exception which will not count as a failure in terms of circuit breaker and metrics. As seen in documentation:
Unlike all other exceptions thrown by a HystrixCommand this will not
trigger fallback, not count against failure metrics and thus not
trigger the circuit breaker.
Instances of HystrixBadRequestException are not created by Hystrix itself, so it is safe to use it as a wrapper for business exceptions. However, original business exception still requires to be unwrapped.
new HystrixCommand<BusinessResponse>() {
#Override
protected BusinessResponse run() throws Exception {
try {
return doStuff(...);
} catch (BusinessException e) {
throw new HystrixBadRequestException("Business exception occurred", e);
}
}
}
.observe()
.onErrorResumeNext(e -> {
if (e instanceof HystrixBadRequestException) {
e = e.getCause(); // Unwrap original BusinessException
}
return Observable.error(e);
})
Related
I want to throw Exceptions that are extended from Exception if Try.ofCallable() fails.
I have a callable of the type:
final Callable<MyResponse> decoratedCallable =
circuitBreakerService.getDecoratedMethod(
myArg1,
() -> myFunction(myArg1, myArg2, myArg3)
);
I am trying something like this:
Try.ofCallable(decoratedCallable).onFailure(throwable -> {
if (throwable instanceof CallNotPermittedException) {
throw new MyRuntimeExceptionA("msg1", throwable);
} else {
throw new MyRuntimeExceptionB("msg2", throwable);
}
});
This works (the function that wraps the above two statements throws the correct exception MyRuntimeExceptionA and MyRuntimeExceptionB) if both MyRuntimeExceptionA and MyRuntimeExceptionB extend RuntimeException, but not if they extend Exception.
If they extend Exception then I am not able to throw them from the main function.
The IDE asks to wrap them in try/catch - which I don't want.
You have two options. You can throw when you try to unwrap the Try by getting the value with the following code:
Try.ofCallable(decoratedCallable)
.getOrElseThrow(throwable -> {
if (throwable instanceof CallNotPermittedException) {
return new MyExceptionA("msg1", throwable);
} else {
return new MyExceptionB("msg2", throwable);
}
})
or move out the error mapping code to before unwrapping with a similar code:
Try.ofCallable(decoratedCallable)
.mapFailure(
Case(
$(instanceOf(CallNotPermittedException.class)),
throwable -> new MyExceptionA("msg1", throwable)
),
Case($(), throwable -> new MyExceptionB("msg2", throwable))
)
.get()
Both solutions will only throw when unrwapping, so if you want to throw early, you will have to unwrap early.
Otherwise, I would take the advice others posted in comments not to throw exceptions if you are using Try. The whole point in using Try is to work with total functions instead of partial functions that can throw exceptions.
I don't know much about vavr, but looking in the javadoc for the library, you can see the onFailure method takes a Consumer<? super Throwable> as a parameter. The problem is that consumers do not declare checked exceptions, so you will never be able throw checked exceptions from your lambda.
That being said, what I generally do in these cases is I create a "wrapping" class that will accept checked exceptions, all this wrapping class will do is catch any checked exceptions and wrap them in a runtime exception. For example:
public class ThrowingConsumerHelper {
public static <T> Consumer<T> throwingConsumer(
ThrowingConsumer<T> consumer) {
return object -> {
try {
consumer.accept(object);
} catch (Throwable t) {
throw new RuntimeException(t);
}
};
}
#FunctionalInterface
public interface ThrowingConsumer<T> {
void accept(T t) throws Exception;
}
}
And then use this like this:
import static ThrowingConsumerHelper.throwingConsumer;
public static void main(String[] args) {
onFailure(throwingConsumer(object -> { throw new Exception("Bug"); }));
}
public static void onFailure(Consumer<? super Throwable> consumer) {
// Do something
}
I have recently started using RxJava2 in one of my projects and currently I am working on implementing error handling in it.
I have written a mock class below in which I was initially throwing the error after wrapping it in a custom exception. However some of the examples I came across on error handling on stackoverflow and other sites used Single.error instead.
I used both approaches and they resulted in my subscribers onError method being invoked with the / by zero exception. I didn't notice any difference between the two.
There is comprehensive documentation on Error Handling and Error Handling Operators along with a lot of other articles on how to handle the exception after it is thrown. But the information in the javadoc for Single.error and Observable.error is quite minimal.
Is there an advantage of using Single.error or Observable.error over just throwing the exception? When do we choose one approach over the other?
public class Test {
public static void main(String[] args){
Single.just(1)
.flatMap(x -> externalMethod(x))
.subscribe(
s -> System.out.println("Success : " + s),
e -> System.out.println("Error : "+e)
);
}
public static Single<Integer> externalMethod(int x){
int result = 0;
try{
/* Some database / time consuming logic */
result = x % 0;
}
catch (Exception e){
throw new CustomException(e.getMessage()); // --> APPROACH 1
OR
return Single.error(new CustomException(e.getMessage())); // --> APPROACH 2
}
return Single.just(result);
}
}
Actually it does not matter, becaues RxJava tries to catch and relay all Throwables
APPROACH 1 -- throw new CustomException();
(io.reactivex.internal.operators.single.SingleFlatMap)
#Override
public void onSuccess(T value) {
SingleSource<? extends R> o;
try {
o = ObjectHelper.requireNonNull(mapper.apply(value), "The single returned by the mapper is null");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
downstream.onError(e);
return;
}
if (!isDisposed()) {
o.subscribe(new FlatMapSingleObserver<R>(this, downstream));
}
}
You see here, that given mapper from flatMap is invoked with an try-catch. If the mapper throws a Throwable, the Throwable will be forwarded via onError to downstream subscriber.
APPROACH 2 -- return Single.error(...)
(io.reactivex.internal.operators.single.SingleError)
Single#error
#Override
protected void subscribeActual(SingleObserver<? super T> observer) {
Throwable error;
try {
error = ObjectHelper.requireNonNull(errorSupplier.call(), "Callable returned null throwable. Null values are generally not allowed in 2.x operators and sources.");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
error = e;
}
EmptyDisposable.error(error, observer);
}
public static void error(Throwable e, SingleObserver<?> observer) {
observer.onSubscribe(INSTANCE);
observer.onError(e);
}
Single#error emits given Throwable on subscription via #onError
When a value is emitted to Single#flatMap the mapper is applied and a subscription is opened returned value from the mapper.
(io.reactivex.internal.operators.single.SingleFlatMap.SingleFlatMapCallback.FlatMapSingleObserver)
#Override
public void onSubscribe(final Disposable d) {
DisposableHelper.replace(parent, d);
}
#Override
public void onError(final Throwable e) {
downstream.onError(e);
}
The returned Single returns a Single#error, which emits a Throwable via #onError. Given #onError will be delegated to the downstream subscriber via onError.
Performance wise one could be faster than the other, but this must be measured to have an exact image. Returning Single#error does more allocations and has more methods on the Stack (subscribeActual). On the other side, when throwing a Throwable it must be caught and handeled.
Therefore in my opinion it acutally does not matter, whether you use the one or the other.
I would like to two have two different methods running in catch and final blocks. I have found AutoCloseable interface, but I need something to fire in case of exception only.
Like:
SomeService service = CreateService().andOpenTransaction()
try {
service.doSomeMessyThingsInsideDB();
} catch (Exception e) {
service.rollbackTransaction();
throw e;
} finally {
service.closeConnection();
}
Is there any way to make it simpler? As I said I am familiar with AutoCloseable, but it helps me only with finally block. I still cannot use it inside the catch.
Well you could define your own interface, and then some static runner method:
public interface ErrorHandlingCloseable extends AutoCloseable {
void run() throws Exception;
void onError(Exception e);
static void execute(ErrorHandlingClosable ehc) throws Exception {
try(ErrorHandlingClosable temp = ehc) {
ehc.run();
} catch(Exception e) {
ehc.onError(e);
throw e;
}
}
}
Which you then could then call like this:
SomeService service = CreateService().andOpenTransaction();
ErrorHandlingCloseable.execute(new ErrorHandlingCloseable() {
public void run() throws Exception { service.doSomeMessyThingsInsideDB(); }
public void onError(Exception e) { service.rollbackTransaction(); }
public void close() throws Exception { service.closeConnection(); }
});
But you see, it's still messy.
You could even implement this interface in your SomeService but then you're restricted that the run() method will always call doSomeMessyThingsInsideDB().
Another way but still similar would be to use Java8 and create a helper functional interface:
public interface ThrowingRunnable {
void run() throws Exception;
}
And then a static method somewhere:
public static void execute(ThrowingRunnable action,
ThrowingRunnable onCatch,
ThrowingRunnable onFinally) throws Exception {
try(AutoCloseable ao = onFinally) {
action.run();
} catch(Exception e) {
onCatch.run();
throw e;
}
}
The interesting part is probably this: try(AutoCloseable ao = onFinally), which "registers" your onFinally method to be called when finally is reached.
This could then be called like this:
execute(
service::doSomeMessyThingsInsideDB,
service::rollbackTransaction,
service::closeConnection
);
You said you are familiar with AutoCloseable, but you don't use it.
Have you considered using try-with-resources statement?
Your code can be simplified to:
try (SomeService service = CreateService().andOpenTransaction()) {
service.doSomeMessyThingsInsideDB();
} catch(exception e){
service.rollbackTransaction();
throw e;
}
Oracle has great doc for that, including examples.
Note: A try-with-resources statement can have catch and finally blocks just like an ordinary try statement. In a try-with-resources statement, any catch or finally block is run after the resources declared have been closed.
Answering your question, this is as simple as it can get.
If your class doesn't implement Closeable then you can either implement it or use finally.
First step: Handling the exception
You evidently want the exception handled before some close. Then you need inside a try-with-resources to handle the exception.
/** throws RuntimeException */
void process(Callable<Void> work, Consumer<Exception> onFail) {
try {
work.call();
} catch (Exception e) {
onFail(e);
}
}
try (SomeService service = CreateService().andOpenTransaction()) {
process(() -> service.doSomeMessyThingsInsideDB(),
e -> {
service.rollbackTransaction();
throw new IllegalStateException(e);
});
}
This is not very satisfactory, but again also integrating the AutoCloseable, might give too few use-cases.
Second step: with AutoCloseable
<SV extends AutoCloseable> void processAutoClosing(Supplier<SV> serviceFactory,
Callable<Void> work, Consumer<Exception> onFail) {
try (SV service = serviceFactory.get()) {
process(work, onFail);
}
}
processAutoClosing(...);
Is there a way to have an Observable just throw an exception that occurs from within a function like flatMap()?
In Java, on a normal function, you can specify that it may throw an exception:
public void dangerousFunction() throws IOException {}
Within an Observable function like flatMap(), I can't seem to find a similar syntax. I can use a try/catch like this:
myObservable.flatMap(() -> {
try {
return dangerousFunction();
} catch (IOException e) {
return Observable.error(e);
}
});
Is there a cleaner method for writing that? If I have lots of maps and/or Observables, that winds up being a lot of try/catch blocks cluttering up my code.
The standard approach to dealing with exceptions in a RxJava map() method is propagate the exception by catch-and-throw. For example:
.map(b -> {
try {
...
} catch (IOException ex) {
// manual catch and throw
throw new RuntimeException(ex);
// or catch-and-throw using a built-in helper
throw Exceptions.propagate(e);
}
})
This can be get quite verbose when repeated across multiple map() calls so you could define a helper to wrap this behaviour e.g.
observable.map(RxMapWrapper.wrapAndThrow(new RxMapWrapper.Func1Wrapper<A, B>() {
#Override
public B call(A document) throws Exception {
// your map logic here ...
}
}))
public class RxMapWrapper {
public static <T, R> Func1<T, R> wrapAndThrow(Func1Wrapper<T, R> caughtFunction) {
return t -> {
try {
return caughtFunction.call(t);
} catch (Exception e) {
throw Exceptions.propagate(e);
}
};
}
public interface Func1Wrapper<T, R> extends Function {
R call(T t) throws Exception;
}
}
If you only want to return Observable.error(e) inside catch blocks, you don't need try/catch at all. Exception would go to downstream and .subscribe(,throwable) will catch it anyway.
If you want to return some other/default object when error occurred, try these operators: onErrorReturnItem, onErrorResumeNext, onErrorReturn. This would be cleaner.
Other option would be implementing this onErrorReturnItem mechanism into your methods itself instead of throwing Exception.
What is the requirement in a Service implementation so that the ErrorCallback will be able to print the error message on the UI like.
I tried injecting a ErrorCallback in the Service call code, and when I print the Message object its null.
What should be the Service implementation look like, should I put throws SomeException on the implementation method? Or?
myService.call(new RemoteCallback<String>() {
#Override
public void callback(String response) {
Multimap<String, String> state = ArrayListMultimap.create();
state.put("hash", response);
submit.go(state);
}
}, new ErrorCallback() {
#Override
public boolean error(Message message, Throwable throwable) {
throwable.printStackTrace();
Window.alert("Error: " + message);
return false;
}
}).createmy(my);
Your code should work as stated in the question. The exception thrown by the remote service should be delivered to you in the throwable parameter to your ErrorCallback.error() method.
You only need to put a throws clause on the remote interface if you want to throw a checked exception. Unchecked exceptions should work as you've done it. In fact, there is a disadvantage to declaring checked exceptions on remote interfaces: you will have to surround your RPC calls with a useless try/catch block, like this:
#Remote public interface MyService {
Result dangerousOperation() throws MyCheckedException;
}
and the calling code:
try {
myService.call(new RemoteCallback<Result>() {
#Override
public void callback(final Result result) {
Window.alert("Yay, got a result: " + result);
}
},
new BusErrorCallback() {
#Override
public boolean error(Message message, Throwable throwable) {
Window.alert("Got an exception from the remote service: " + throwable);
return false;
}
}).dangerousOperation();
}
catch (MyCheckedException e) {
throw new AssertionError(); // can't happen: caller stub won't throw this
}
So you're probably better off with the unchecked exception.