From a quarkus (kotlin) appli, I request multiple endpoints (same endpoint but with different base URL) in parallel, then I combine the uni in order to not wait sequentially for each response.
Here is a sample:
val unis = repository.findUnis()
?.sites
?.map { site ->
RestClientBuilder.newBuilder()
.baseUri(URI.create(site.url))
.build(MyClientService::class.java)
.api("param")
.ifNoItem()
.after(Duration.ofMillis(1))
.recoverWithItem(null)
.onFailure()
.invoke {
logger.info("Error while connecting to ${site.url}", it)
}
.onFailure()
.recoverWithItem(null as? String)
}
return Uni.combine().all().unis<String>(unis)
.combinedWith { it as (List<String?>?) }
.await().atMost(Duration.ofMillis(1))
?.filterNotNull()
The problem I have is that the ifNoItem
is not used in case of Timeout. If a single uni takes more than 1 millisecond (this value is for tests only...) then the last block throws a TimeoutException at combinedWith(...).await()
.
I'd like to treat the timeout at the single uni level, and this error to be considered as a failure (and to be logged and recovered). But this doesn't seem to work. My implementation comes from https://smallrye.io/smallrye-mutiny/#_how_do_i_handle_timeout).
How to do it properly?
Instead of
.ifNoItem().after(Duration.ofMillis(1)).recoverWithItem(null)
, use:.ifNoItem().after(Duration.ofMillis(1).fail()
which will propagate the failure.