Is it reasonable to throw an exception from an asynchronous method? - java

Developing in Java an asynchronous method with a CompletableFuture return type we expect the resulting CF to complete normally or exceptionally depending on whether that method succeeds or fails.
Yet, consider for instance that my method writes to an AsynchronousChannel and got an exception opening that channel. It has not even started writing. So, in this case I am tenting to just let the exception flow to the caller. Is that correct?
Although the caller will have to deal with 2 failure scenarios: 1) exception, or 2) rejected promise.
Or alternatively, should my method catch that exception and return a rejected promise instead?

IMO, option 1) makes the API harder to use because there will be two different paths for communicating errors:
"Synchronous" exceptions, where the method ends the an exception being thrown.
"Asynchronous" exceptions, where the method returns a CF, which completes with an exception. Note that it is impossible to avoid this case, because there will always be situations where the errors are only found after the asynchronous path has started (e.g. timeouts).
The programmer now has to ensure both these two paths are correctly handled, instead of just one.
It is also interesting to observe that the behaviour for both C# and Javascript is to always report exceptions thrown inside the body of an async function via the returned Task/Promise, even for exceptions thrown before the first await, and never by ending the async function call with an exception.
The same is also true for Kotlin's coroutines, even when using the Unconfined dispatcher
class SynchronousExceptionExamples {
#Test
fun example() {
log.info("before launch")
val job = GlobalScope.launch(Dispatchers.Unconfined) {
log.info("before throw")
throw Exception("an-error")
}
log.info("after launch")
Thread.sleep(1000)
assertTrue(job.isCancelled)
}
}
will produce
6 [main] INFO SynchronousExceptionExamples - before launch
73 [main #coroutine#1] INFO SynchronousExceptionExamples - before throw
(...)
90 [main] INFO SynchronousExceptionExamples - after launch
Note as the exception occurs in the main thread, however launch ends with a proper Job.

I think both are valid designs. Datastax actually started their design with first approach, where borrowing a connection was blocking, and switched to fully async model (https://docs.datastax.com/en/developer/java-driver/3.5/upgrade_guide/#3-0-4)
As a user of datastax java driver I was very happy with the fix, as it changed the api to be truly non-blocking (even opening a channel, in your example, has a cost).
But I don't think there are right and wrong here...

It doesn't make a big difference from the callers point of view. In either case there will be visibility of the cause of the exception whether it it thrown from the method or from calling get() on the completable future.
I would perhaps argue that an exception thrown by the completable future should be an exception from the async computation and not failing to start that computation.

Related

How to call independent functions parallel and throw exception if one fails using CompletableFuture

I am try to do something like
Optional<Order> orderDetails = orderRepository.findById(orderId);
if (orderDetails.isEmpty())
throw new OrderNotFoundException("Order not found!");
Optional<User> UserDetails = userRepository.findById(userId);
if (UserDetails.isEmpty())
throw new UserNotFoundException("User not found!");
List<OrderItem> ItemDetailsList = orderItemRepository.findByOrderIdOrderByItemIdAsc(orderId);
Where I want to call these three Services methods together in a non-blocking way, but I want to throw error if any one of those call fails and dont proceed furthur.
If all of the above works, then execute the later logic.
I am thinking of using allOff() then after that use get on the Futures and do the above logic of throwing error when the Optional is empty?
Is there better way of doing it ? i.e if one of them fails and others are still running, throw error and abort the other running tasks.
CompletableFuture is the wrong tool for the job here. And the main problem is that you want:
"...throw error and abort the other running tasks"
If you read what CompletableFuture::cancel documentation says, you will see that:
mayInterruptIfRunning – this value has no effect in this implementation because interrupts are not used to control processing.
So, even if you call cancel, this will not interrupt your tasks, they will still continue to completition. As such, your fundamental requirement can not be met.
There is a way with creating a custom pool of threads for that CompletableFuture that you want to cancel and shut down the pool, as an example here. But this is not trivial to do and your threads need to respond to interrupts properly.

Java exception design : must be caught or declared to be thrown => Too much code impact

Disclaimer : I'm coming from C# world so this is question might be biased by my previous experience
I have a method that is initializing logging. If this fails, the rest of the app should not run as any call to logger will throw a NullPointerException.
Today, my code is catching the exception and printing an error log via System.err. To me, this is a mistake, it should let the exception propagate up until it kills the app.
So I started removing the try catch and I suddenly got complains from the compiler saying that I should declare my exception on the whole stack where this method is called.
I understand the logic behind it and used to found it practical : you know how this method is capable of failing.
However, that doesn't sound right to me in term of separation of responsibility. I don't want the upper layers to be aware of this potential IOException fail, it is a very specialized behavior that shouldn't be known to , for example, the main method.
And, if we push this logic, it means that :
the highest layer will eventually have to declare the whole scope of exceptions (From IO to Network to custom exceptions...)
Any addition of a new exception can potentially impact a lot of files and code
Am I missing something or this is intended exception design ?
I think what you are looking for is not a Java Exception, it is a Java Error.
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions. The ThreadDeath error, though a "normal" condition, is also a subclass of Error because most applications should not try to catch it.
https://docs.oracle.com/javase/7/docs/api/java/lang/Error.html
You can throw a error, which indicates that your app won't work anymore, which you declared as correct behaviour.
You can encapsulate your checked exception in a RuntimeException (or one if its children), which does not force you to declare the exception:
public X execute() {
try {
return someThrowingMethod();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
If you can't initialize the logger and this is an enterprise application, I recommend killing your application with an exit code that explains the reason. If this is a client application, I recommend showing a message to the client stating the problem, recommending to the client that you report this back to you, and allowing them the choice of whether to proceed or not

Java: How to handle bad method arguments?

I'm writing a method with the following signature:
public void setCell(int index, String value);
The problem with this method is that the index parameter has a finite range decided at runtime, and the caller may accidentally use an out-of-bounds value for it. What should I do in this case?
I can think of three options:
Nothing -- let the whole thread crash and burn with an uncaught runtime exception
Immediately return if the index is out of bounds -- the caller will be unaware that the method failed but the program won't crash
Throw an exception / force the user to wrap calls in a try/catch block. This seems a bit overkill and tedious for the user of the method
In general, how do you decide which of these options to use?
Ideally, you'd want to throw an exception as early as possible (fail-fast) or let the exception happen naturally in which case it would hoist or bubble up to the calling method to indicate the cause of the exception rather than trapping the exception in a try/catch and letting the execution continue.
I'd also avoid option 2 which immediately returns if the index is out of bounds due to the fact that it's now impossible for the calling method to know if execution has successfully completed or not. in-fact this is a means of helping the program hide a bug rather than trying to signal it, which in a way relates to JB Nizet's comment.
It's better to keep the caller informed if the method being invoked successfully finished doing its logic or for some reason, it failed to do so.
throw an exception
You can even implement your own exceptions. Which case to use depends on your application and application design. Having uncaught or unhandled exceptions is probably the worst case most of the time.
if you have an user interface you can usually handle exceptions and inform the user, if you are implementing library functions you'll rather throw them and pass them to a higher level.

Should I ever throw a retriable exception from my service

My service is DService and I am fourth link in the chain of services i.e. the call flow is
Online User -> AService -> BService -> CService -> DService -> EService.
When I invoke EService from DService, it can throw retriable exception like HttpTimeoutException. I typically retry 2-3 three times and throw back an exception if it fails even after 2-3 retries.
My question is, the exception which I am throwing to CService, should that be retriable or non-retriable? Please find below my evaluation of Pros & Cons of both options
Cons of Throwing Retriable exception from DService
- If DService throws a retriable exception, following the same convention CService also might retry DService 2-3 times and in each call of C-D, D will again try 2-3 times onto E service call. Likewise the calls ultimately to EService will increase exponentially as we go up the call chain. So If EService network was indeed down for long time, we are talking about long number of un-necessary calls. This can be mitigated by having timeouts for each call in the chain, still not sure if that's a enough mitigation against un-necessary number of calls.
Pros of Throwing Retriable exception from DService
- CService will retry after sometime as in the subsequent retries we might get correct value (within the time limits)
- Especially if the clients are some backend jobs, then they can exponentially retry for long time before giving up. Throwing Un-Retriable exception would weed out this option
Please provide your views and suggestions on this
Thanks,
Harish
Without knowing what the services do, whether or not DService should retry or CService should, I cannot say for sure. However my philosophy is that the service being called should not be the one to retry, ever. In this case, EService would throw an exception stupidly and without any handling whatsoever. The reason behind this is because the end of the chain should be stateless and should not make decisions on behalf of the caller.
The caller can dictate to a certain extent within the confines of what is acceptable and what isn't on whether the error should be reattempted or not. In other words, if EService attempts to perform a connection to a database and DService is performing a lookup service, then it may be in the scope of DService to say, if a certain information isn't found in a certain table, to check in another table instead. However, failure to connect to the database by EService flies over the head of DService, whose scope is simply to return information requested by CService.
CService, having made the call to retrieve certain information, depending on what it does, may then receive the database connection and attempt to retry a number of times after a delay because it is performing a batch work on that data and will continue to retry until the database is back online. Or, if it is retrieving information to show to the user on a webpage, must fail fast and deal with the database connection error by presenting a nice error message to the user instead.
It entirely depends on what your services do and where their responsibilities lie. Likewise, whether an exception is retriable or not should again depend on the caller's necessity, not the service itself. It is perfectly viable to present a retriable exception to the caller that is only attempted once.
Hope that helps!
I think throwing retriable exceptions is a viable approach if you define exponentially increasing retry-periods up on the chain.
I'd say you shouldn't retry in DService in the first place, because, as you say, if each service did that you could be facing trouble. Hence, let the exception bubble up the call stack and let it be handled at the outer most service possible; could even be the user.
Rationale: Why would it be on DService to decide if CService, BService or AService would want to retry or not?
However, I think it also depends on the frequency of the exception and the success rate of retries. If the exception occurs frequently but the call usually succeeds upon the first or second retry it's another thing than an exception which happens once a day and/or retrying is futile most of the time.
What you throw at your invokers, and whether what you throw at them will also carry a suggestion "but you could retry this", should be determined by the intended semantics of your service exclusively.
(Besides, I have never heard of java Exception objects formally carrying any such property, but that might be because I'm lagging behind a bit.)
EDIT.
Whether you "retry" an operation that failed, is for you (and you alone) to decide. However, if you do decide to retry, it is also your responsibility to decide after how many failures you are going to stop retrying and call it a day, and at that point it is most certainly unwise to throw an exception to your caller that suggests he can "retry" as well.

Not-an-exception exception in Java?

Does java has library exception class which means actually not an error, but good termination? I know I can make my own class or use null, but wish to know.
EDIT 1
I want to use exception object as an old fashion return code for a method, so I need something equivalent to ERROR_SUCCESS code in Win32 API.
Exceptions in Java are meant to be used for abnormal termination only. Using them to flag correct termination should be considered really bad practice.
You might use return values instead.
To directly answer your question: No. There is no standard Java exception that means "this is a normal termination".
If you wanted to, you could define a custom exception that meant this for your application.
However,
... using an exception for "normal control flow" goes against the strong recommendations of the Java designers, and a Java "Best Practice" rule that has pretty much universal acceptance. This is not to say you should NEVER do this. It is just that the cases where it is justifiable to do this are VERY RARE. (And you'd need to take special steps to avoid grossly inefficient code ... )
Anyway, the fact that it is (almost) always a terrible idea to use exceptions for normal flow control explains why a standard exception was never created. The Java designers clearly didn't want to appear to be encouraging this practice.
The closest thing to a "good termination" signal I can think of is not an exception, but a call to System.exit(int) with 0 as argument, to indicate to the operating system that the program ended successfully. From the javadocs:
Terminates the currently running Java Virtual Machine. The argument serves as a status code; by convention, a nonzero status code indicates abnormal termination. This method calls the exit method in class Runtime. This method never returns normally.
As has been pointed out, an exception is not to be used to inform of a "good termination", quite the contrary.
No. Exception means exceptional situation. You should structure your program flow so that exceptions are thrown only for exceptional situations, rather than on the normal flow.
So, if you want to return "success": return true or some enum Result.SUCCESS.
Exceptions are mean to denote that something went wrong. Different exceptions depict different items which went wrong and will thus cause the program to terminate if not handled. Something successfully finishing is not an exception.
I think what you need to do is to either return a particular value, or else, make your application fire some sort of event. In this case throwing exception is not (at least for me) recommended.
Depends what you define as "good termination" I guess - is a security exception good because it stopped someone from hacking your system? It's not really an error, but it is an abnormal situation that you need to handle.
In general exceptions are designed to be used for exceptional conditions only (which may or may not be an error in your code - it could mean that some resource is unavailable, or a security check failed etc.)
If you are using exceptions for regular control flow (i.e. they are getting thrown in normal, expected circumstances) then you are probably doing something wrong.
Maybe you mean an InterrupedException? This one is thrown, when you wish to terminate a thread gracefully.
As some other responses said, when there is no exception, nothing is raised.
Therefore, you can just your code for the "no-exception" into the try block after the rest of instructions. Something like:
try{
//code here
//code of no exception
}catch(Exception e){
//nothing or exception code
}
or you can just create your own exception by doing a class that extends Exception

Categories

Resources