使用vertx http客户端时,可观察的ZIP运算符挂起

时间:2017-04-13 12:26:01

标签: rx-java vert.x connection-reset http-pipelining vertx-httpclient

我做了什么:

我使用vertx rx http客户端来执行大量HTTP请求。在这个特定的情况下,我调用“方法A”,它返回一个ID列表。接收我需要多次调用方法A的所有ID以获得下一批结果。 (每次我指定一个不同的页码我想收到)

为了提高性能并尽可能并行地进行调用,我创建了一个(RxJava)Observables项目列表,每个项目代表单个页面请求的结果。当我完成创建此列表时,我调用Obserable.zip运算符并传递observable列表。

问题:

使用没有特殊设置的vertx http客户端一切正常但非常慢。例如3000个http请求将在5分钟内处理完毕。

我尝试通过设置vertx http客户端选项来提高性能,如下所示:

 HttpClientOptions options = new HttpClientOptions();

 options.setMaxPoolSize(50)
        .setKeepAlive(true)
        .setPipelining(true)
        .setTcpKeepAlive(true)
        .setPipeliningLimit(25)
        .setMaxWaitQueueSize(10000);

但是当我这样做时,我会得到不稳定的结果:有时一切正常,我能够在不到20秒的时间内收到所有回复。但是,有时我调用的外部服务器关闭连接,日志显示以下错误:

io.vertx.core.http.impl.HttpClientRequestImpl
SEVERE: io.vertx.core.VertxException: Connection was closed
  • 我的代码中没有错误处理程序被称为
  • 当出现此错误时,zip操作符挂起

以下是创建HttpClientRequest

的代码
public Observable<HttpRestResponse> postWithResponse(String url, Map<String, String> headers, String body) {
        Observable<HttpRestResponse> bufferObservable = Observable.create(subscriber -> {
            try {
                HttpClientRequest request = httpClient.postAbs(url);
                addHeadersToRequest(headers, request);
                sendRequest(url, subscriber, request, body);
            }catch (Exception e) {
                try {
                    subscriber.onError(e);
                }catch (Exception ex) {
                    logger.error("error calling onError for subscriber",ex);
                }finally {
                    subscriber.onCompleted();
                }
            }
        });
        return bufferObservable;
    }

private void sendRequest(String requestUrl, Subscriber<? super HttpRestResponse> subscriber, HttpClientRequest request, String bodyData) {
        final long requestId = reqNumber.getAndIncrement();

        if (bodyData != null) {
            request.putHeader("Content-Length", String.valueOf(bodyData.getBytes().length);
        }

        request.putHeader("Accept-Encoding", "gzip,deflate");

        Observable<HttpRestResponse> retVal = request.toObservable()
                .doOnError(throwable -> {
                    logger.error("<<< #: " + requestId + " HTTP call failed. requestUrl [" + requestUrl + "] reason:" + throwable.getMessage());
                }).doOnNext(response -> {
                    if (response != null) {
                        logger.debug(" <<< #: " + requestId + " " + response.statusCode() + " " + response.statusMessage() + " " + requestUrl);
                    }
                }).flatMap(httpClientResponse -> {
                    try {
                        if (httpClientResponse != null && doCheckResponse(httpClientResponse, requestUrl, requestId, bodyData)) {
                            Observable<Buffer> bufferObservable = httpClientResponse.toObservable()
                                    .reduce(Buffer.buffer(1000), (result, buffer) -> result.appendBuffer(buffer));

                            return bufferObservable.flatMap(buffer -> Observable.just(new HttpRestResponse(buffer, httpClientResponse)));
                        }
                    } catch (Exception e) {
                        logger.error("error in RestHttpClient", e);
                    }

                    return Observable.just(new HttpRestResponse(null, httpClientResponse));
                });

        retVal.subscribe(subscriber);

        if (bodyData != null) {
            request.end(bodyData); // write post data
        } else {
            request.end();
        }
    }

asdasdasd

2 个答案:

答案 0 :(得分:0)

如果您认为可以像这样挂钩您的异常逻辑

 try {
            HttpClientRequest request = httpClient.postAbs(url);
            addHeadersToRequest(headers, request);
            sendRequest(url, subscriber, request, body);
        }catch (Exception e) {
            try {
                subscriber.onError(e);
            }catch (Exception ex) {
                logger.error("error calling onError for subscriber",ex);
            }finally {
                subscriber.onCompleted();
            }
        }

您不会收到任何错误,因为基本上所有处理现在都停留在Rx生态系统中,因此您的try catch块中没有任何内容会报告给您。

从这个时间点出现的错误将来自你的

bufferObservable.onErrorReturn()

bufferObservable.subscribe(success, error)

答案 1 :(得分:0)

所以最后我想出来了。看来我把Observable.zip方法传递给了一个空列表...

这里的问题是onNext或onError没有在“zip”方法的返回的observable对象上调用。在这种情况下,只调用onComplete,我没有费心为...创建处理程序。

非常感谢所有感兴趣并希望提供帮助的人。

参见Yaniv