将许多ReactiveX流组合到一个结果流中

时间:2018-06-08 11:27:05

标签: java asynchronous rx-java2 reactivex

我正在尝试使用RxJava了解ReactiveX,但我无法获得整个Reactive的想法。我的情况如下:

我有Task课程。它具有perform()方法,该方法正在执行HTTP请求并通过executeRequest()方法获得响应。该请求可以被执行多次(定义的重复次数)。我想获取executeRequest()的所有结果并将它们合并到Flowable数据流中,以便我可以在Flowable方法中返回此perform()。所以最后我想让我的方法返回我Task执行的请求的所有结果。

executeRequest()返回Single因为它只执行一个请求,并且可能只提供一个响应或者根本不提供响应(如果超时)。 在perform()中,我为每次重复创建Flowable个数字范围。订阅此Flowable我每次重复执行一次请求。我还订阅了每个响应Single,用于记录和收集响应到集合中以供日后使用。现在我有一组Single,如何将它们合并到Flowable以便在perform()中返回?我试图使用像merge()这样的运算符,但我不了解它的参数类型。

我已经在网上阅读了一些指南,但它们都非常笼统,或者根据我的情况不提供示例。

public Flowable<HttpClientResponse> perform() {

    Long startTime = System.currentTimeMillis();

    List<HttpClientResponse> responses = new ArrayList<>();
    List<Long> failedRepetitionNumbers = new ArrayList<>();

    Flowable.rangeLong(0, repetitions)
            .subscribe(repetition -> {
                logger.debug("Performing repetition {} of {}", repetition + 1, repetitions);

                Long currentTime = System.currentTimeMillis();

                if (durationCap == 0 || currentTime - startTime < durationCap) {

                    Single<HttpClientResponse> response = executeRequest(method, url, headers, body);

                    response.subscribe(successResult -> {
                                logger.info("Received response with code {} in the {}. repetition.", successResult
                                        .statusCode(), repetition + 1);
                                responses.add(successResult);
                            },
                            error -> {
                                logger.error("Failed to receive response from {}.", url);
                                failedRepetitionNumbers.add(repetition);
                            });
                    waitInterval(minInterval, maxInterval);
                } else {
                    logger.info("Reached duration cap of {}ms for task {}.", durationCap, this);
                }
            });

    return Flowable.merge(???);
}

executeRequest()

private Single<HttpClientResponse> executeRequest(HttpMethod method, String url, LinkedMultiValueMap<String, String>
        headers, JsonNode body) {

    CompletableFuture<HttpClientResponse> responseFuture = new CompletableFuture<>();

    HttpClient client = vertx.createHttpClient();
    HttpClientRequest request = client.request(method, url, responseFuture::complete);
    headers.forEach(request::putHeader);
    request.write(body.toString());
    request.setTimeout(timeout);
    request.end();

    return Single.fromFuture(responseFuture);
}

1 个答案:

答案 0 :(得分:1)

不要在perform方法中订阅每个observable(每个HTTP请求),而是继续链接这样的observable。您的代码可以简化为。

    public Flowable<HttpClientResponse> perform() {
    // Here return a flowable , which can emit n number of times. (where n = your number of HTTP requests)
    return Flowable.rangeLong(0, repetitions) // start a counter
            .doOnNext(repetition -> logger.debug("Performing repetition {} of {}", repetition + 1, repetitions)) // print the current count
            .flatMap(count -> executeRequest(method, url, headers, body).toFlowable()) // get the executeRequest as Flowable
            .timeout(durationCap, TimeUnit.MILLISECONDS); // apply a timeout policy
    }

最后,您可以在实际需要执行此操作的地方订阅perform,如下所示

             perform()
            .subscribeWith(new DisposableSubscriber<HttpClientResponse>() {
                @Override
                public void onNext(HttpClientResponse httpClientResponse) {
                  // onNext will be triggered each time, whenever a request has executed and ready with result
                  // if you had 5 HTTP request, this can trigger 5 times with each "httpClientResponse" (if all calls were success)
                }

                @Override
                public void onError(Throwable t) {
                    // any error during the execution of these request,
                    // including a TimeoutException in case timeout happens in between
                }

                @Override
                public void onComplete() {
                   // will be called finally if no errors happened and onNext delivered all the results
                }
            });