Search code examples
kotlinreactive-programmingquarkusquarkus-rest-clientmutiny

Mutiny: recover from a single uni timeout


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?


Solution

  • Instead of .ifNoItem().after(Duration.ofMillis(1)).recoverWithItem(null), use: .ifNoItem().after(Duration.ofMillis(1).fail() which will propagate the failure.