Home > Mobile >  Collect CompletableFuture results in recursive calls
Collect CompletableFuture results in recursive calls

Time:12-14

I have following code, that is getting reports for given time interval from web API that returns CompletableFuture. In case that count of rows for returned report was exceeded, time interval will be splited into 2 half and API will be called for both halfs. This will be recursively repeated until count of rows satisfy condition.

I would like to get CompletableFuture<List<APIResult>> or even better List<CompletableFuture<APIResult>> as result of this method.

My code run ok when there is no need for interval splitting. In case when recursion call is needed it will return just empty list and recursive calls are executed later on asynchronously.

 protected CompletableFuture<List<APIResult<String>>> generateDomainReport(
        ExtendedDomainConfiguration domain,
        ZonedDateTime chunkStartDate,
        ZonedDateTime chunkEndDate,
        List<APIResult<String>> result) {

    CompletableFuture<APIResult<String>> response = runReport(domain.getDomainName(), chunkStartDate, chunkEndDate);
    return response.thenApply(report -> {
        // in case that count of report rows hit the limit, split timeWindow into two half,
        // calculate middle date and run report for both intervals: <startDate, middleDate>; <middleDate, endDate>
        if (isReportMaxRowCountReached(report.getContent(), domain.getMaxReportRowCount())) {
            LOGGER.warn(String.format(
                    "Report limit row counts was reached. "  
                            "Splitting window <%s, %s> into 2 parts and rerunning report",
                    chunkStartDate, chunkEndDate));
            Duration timeWindow = Duration.between(chunkStartDate, chunkEndDate);
            ZonedDateTime chunkMiddleDate = chunkEndDate.minus(Duration.ofSeconds(timeWindow.getSeconds() / 2));
            // recursively repeat until count of returned rows is under the limit
            generateDomainReport(domain, chunkStartDate, chunkMiddleDate, result);
            generateDomainReport(domain, chunkMiddleDate, chunkEndDate, result);
        } else {
            result.add(report);
        }
        return result;
    });
}

I also tried use something like that but it didn't helped:

response
.thenAccept(r -> generateDomainReport(domain, chunkStartDate, chunkMiddleDate, result))
.thenAccept(r -> generateDomainReport(domain, chunkMiddleDate, chunkEndDate, result));

I will be thankful for any idea what I am doing wrong. Thanks

CodePudding user response:

I transformed my original code to something like this and it seems to be working:

protected CompletableFuture<List<APIResult<String>>> generateDomainReport(
            ExtendedDomainConfiguration domain,
            ZonedDateTime chunkStartDate,
            ZonedDateTime chunkEndDate) {

        CompletableFuture<APIResult<String>> response = runReport(domain.getDomainName(), chunkStartDate, chunkEndDate);
        return response.thenApplyAsync(report -> {
            // in case that count of report rows hit the limit, split timeWindow into two half,
            // calculate middle date and run report for both intervals: <startDate, middleDate>; <middleDate, endDate>
            if (isReportMaxRowCountReached(report.getContent(), domain.getMaxReportRowCount())) {
                LOGGER.warn(String.format(
                        "CSV report limit row counts was reached. "  
                                "Splitting window <%s, %s> into 2 parts and rerunning report",
                        chunkStartDate, chunkEndDate));
                Duration timeWindow = Duration.between(chunkStartDate, chunkEndDate);
                ZonedDateTime chunkMiddleDate = chunkEndDate.minus(Duration.ofSeconds(timeWindow.getSeconds() / 2));
                // recursively repeat until count of returned rows is under the limit
                return generateDomainReport(domain, chunkStartDate, chunkMiddleDate)
                        .thenCombineAsync(generateDomainReport(domain, chunkMiddleDate, chunkEndDate),
                                (result1, result2) -> {
                                    List<APIResult<String>> result = new ArrayList<>(result1.size()   result2.size());
                                    result.addAll(result1);
                                    result.addAll(result2);
                                    return result;
                                }).join();
            } else {
                return List.of(report);
            }
        });
    }
  • Related