Search code examples
quarkusmutiny

Collect Uni.combine failures


Is there a way to collect Uni.combine().all().unis(...) failures, as Uni.join().all(...).andCollectFailures() does?

I need to call different services concurrently (with heterogeneous results) and fail all if one of them fails.

Moreover, what's the difference between Uni.combine().all().unis(...) and Uni.join(...) ?


Solution

  • Uni Combine Exception The code should be like this,

    return Uni.combine().all().unis(getObject1(), getObject2()).collectFailures().asTuple().flatMap(tuples -> {
    
                return Uni.createFrom().item(Response.ok().build());
            }).onFailure().recoverWithUni(failures -> {
                System.out.println(failures instanceof CompositeException);
                CompositeException exception = (CompositeException) failures;
                for (Throwable error : exception.getCauses()) {
                    System.out.println(error.toString());
                }
                // failures.printStackTrace();
                return Uni.createFrom().item(Response.status(500).build());
            });
    

    Difference: Quarkus provides parallel processing through use of these two features:

    Unijoin - Iterate through a list of objects and perform a certain operation in parallel. Iterate through a list of orders and perform activities on each order one by one (Multi) OR Iterate through a list of orders and add a method wrapper on the object in the Unijoin Builder. When the builder executes, the method wrappers are called in parallel, and its response collected in a list.

    List<RequestDTO> reqDataList = request.getRequestData(); // Your input data
    UniJoin.Builder<ResponseDTO> builder = Uni.join().builder();
    for (RequestDTO requestDTO : reqDataList) {
        builder.add(process(requestDTO));
    }
    return builder.joinAll().andFailFast().flatMap(responseList -> {
        List<ResponseDTO> nonNullList = new ArrayList<>();
        nonNullList.addAll(responseList.stream().filter(respDTO -> {
            return respDTO != null;
        }).collect(Collectors.toList()));
        return Uni.createFrom().item(nonNullList);
    });
    

    You can see the list of objects converted to method wrapper, 'process', which is then called in parallel when 'andFailFast' is called.

    'Uni.combine' - Call separate methods that returns different response in parallel.

    List<OrderDTO> orders = new ArrayList<>();
    return Uni.combine().all().unis(getCountryMasters(), 
    getCurrencyMasters(updateDto)).asTuple()
        .flatMap(tuple -> {
            List<CountryDto> countries = tuple.getItem1();
            List<CurrencyDto> currencies = tuple.getItem2();
            // Get country code and currency code from each order and 
            // convert it to corresponding technical id.
            return convert(orders, countries, currencies); 
        });
    

    As you see above, both methods in 'combine' returns different results and yet they are performed in parallel.