¿CompletableFuture no cuenta con un método para asignar valores incluso en caso de errores?
Tengo un programa que realiza solicitudes HTTP, donde podría necesitar probar varios servidores diferentes para obtener una respuesta exitosa. El cliente HTTP es asíncrono, por lo que obtengo resultados de CompletableFuture
al realizar las solicitudes.
Puedo intentar fácilmente el “siguiente” servidor cuando obtengo un código de estado de respuesta incorrecto, por ejemplo:
return httpClient.sendAsync(request,
HttpResponse.BodyHandlers.ofByteArray()
).thenCompose(response -> {
if(response.statusCode() == 200){
return completedStage(...); //todo bien, ¡terminado!
}
// intentar el siguiente servidor
return callThisMethodAgain(...);
});
Esto funciona porque thenCompose
espera que el lambda que se le haya proporcionado devuelva otro CompletableFuture
para que pueda encadenar cálculos asíncronos.
Sin embargo, si el servidor no está disponible, el cliente HTTP lanzará una excepción y mi lambda no se ejecutará, lo que hará que la cadena asíncrona termine con esa excepción.
Puedo ver que hay métodos como handle
y handleAsync
, pero no me permiten devolver otro CompletableFuture
, como lo hace thenCompose
. Son algo análogos a thenApply
(es decir, como el map
del stream en lugar de flatMap
), por lo que parece que CompletableFuture
carece del método que sería análogo a flatMap
donde quiero manejar tanto el éxito como los fallos de la acción asíncrona anterior en la cadena.
¿Es eso correcto? ¿Hay alguna solución alternativa que esté pasando por alto?
davy.ai
Sí, tienes razón en que
CompletableFuture
no tiene un método directo análogo aflatMap
en los streams, que pueda manejar tanto casos de éxito como de fallo y devolver otroCompletableFuture
para encadenar. Sin embargo, puedes lograr una funcionalidad similar utilizando el métodohandle
yCompletableFuture.completedFuture
para devolver otroCompletableFuture
para encadenar.Aquí tienes un ejemplo:
En este ejemplo,
handle
toma una BiFunction que maneja tanto laHttpResponse
como laThrowable
devueltas porsendAsync
. Si la respuesta no es nula y tiene un código de estado 200, devuelve unCompletableFuture
completado. Si se lanzó una excepción, devuelve unCompletableFuture
completado que maneja la excepción. De lo contrario, intenta con el siguiente servidor devolviendo una llamada acallThisMethodAgain
.Ten en cuenta que el
thenCompose
al final es necesario para aplanar elCompletableFuture
devuelto porhandle
y permitir una mayor encadenamiento.¡Espero que eso ayude! Déjame saber si tienes alguna otra pregunta.