When I use completeExceptionally I cannot prevent from the thread running it to keep running the code after it.
if I throw an exception after the complete exceptionally then the .get() will catch that exception and not the exception i threw in the completeExceptionally
if(doProcessException){
log.error("before Completeexceptionally called");
cf.completeExceptionally(new StepException("Dummy exception thrown in doProcess",new IOException("dummy IOExcetion in dummy step"), this.getStepName()));
throw new RuntimeException();
}
logs.error("After Completeexceptionally called, why am i running?);
if I completeExceptionally I don't want the code , log.error in my snippet, to run...
I want the thread that ran that logic with the CompletableFuture to stop...
If I run the code above, the empty runtime exception gets caught and not the detailed exception I put in the completeExceptionally()
If I even remove the completeExceptionally() I end up in the same catch on my .get()
If so, what is the purpose of completableFuture.exceptionally(() -> {}) if I have to handle the .get() exceptions anyway?
What ever I wrote in the completeExceptionally I can put in the catch section of my completableFuture.get(), and then I just throw an exception in the runnable, and thus stop any farther progress of that thread.
I'm probably using it incorrectly...
EDIT: Ill give more details as requested in the comments
My scenario is kinda complicated so ill try to simplify it
I have 2 layers, an infrastructue layer that creates a chain of completableFutures with the .thenComposeAsync() method.
after the chain is created i use .get(timeout) to block my infra code and give the entire chain timeout to finish the job.
this .get() forces me to try catch like so
try {
finalEnrichmentResponse = completableFuture.get(enrichmentTimeoutMs, TimeUnit.MILLISECONDS);
endResult = finalEnrichmentResponse.getData();
} catch (InterruptedException e) {
enrichmentException(enrichmentResponse.getData(), finalEnrichmentResponse, e, "Step chain threw InterruptedException");
} catch (ExecutionException e) {
enrichmentException(enrichmentResponse.getData(), finalEnrichmentResponse, e, "Step chain threw ExecutionException...");
} catch (TimeoutException e) {
enrichmentException(enrichmentResponse.getData(), finalEnrichmentResponse, e, "Step chain exceeded the configured timeout: " + enrichmentTimeoutMs + "ms");
}
to my understanding, those catches are if the comletableFuture threw an exception. and doesnt have an .exceptionally() method which is fine by me for safety.
now my issue starts in my logic layer, there i used another completable future for each "step" as i called it in the chain.
the steps in my chain are working synchronically.
so basically i call the method of the step which returns a completableFuture and perform a get() like so
stepResponse = doProcessCf.get();
} catch (EntityStoppedException e) {
//specific handling
} catch (InterruptedException e) {
//specific handling
} catch (Exception e) {
//specific handling
}
here i dont give a timeout since if the actual logic is timeing out its already calculate by the timeout chain...
Im aware this architecture might be bad but this was my first try with completable futures.
since i dont have an completableFuture.exceptionally in the logic layer, if to logic programmer completeEexceptionally() then the catch handles it.
this might be my problem? and i need to add an .exceptionally(() ->{}) to that completableFuture?
anyhow, the thing is that if the comepletableFuture i get from the step, performs somewhere in the code completeExceptionally(), then the rest of the code he wrote after that is still running.
so maybe the solution is just to tell the step programmer to manage his code in a way that if he decides to completeExceptionally() he cant have any code run after it? a single point of return esque instruction.
for simplicity we can assume that the chain only has 1 step.
I thought it can be done in a more elegant way.
Thanks in advance...