I have a program that makes HTTP requests, where I might need to try several different servers to get a successful response. The HTTP client is async, so I get CompletableFuture
results when making requests.
I can easily try the "next" server when I get a bad response status code, for example:
return httpClient.sendAsync(request,
HttpResponse.BodyHandlers.ofByteArray()
).thenCompose(response -> {
if (response.statusCode() == 200) {
return completedStage(...); // all ok, done!
}
// try the next server
return callThisMethodAgain(...);
);
This works because thenCompose
expects the lambda it's given to return another CompletableFuture
so I can chain asynchronous computations.
However, if the server is not available, the HTTP client will throw an Exception and my lambda won't execute and the async chain terminates with that Exception.
I can see there are methods like handle
and handleAsync
, but they don't let me return yet another CompletableFuture
, as thenCompose
does. They are kind of analogous to thenApply
(i.e. like stream's map
rather than flatMap
), so it seems to me CompletableFuture
is missing the method that would be analogous to flatMap
where I want to handle both success and failures from the previous async action in the chain?
Is that correct? Is there some workaround I am missing?