ExecutionException-尝试使用CompletableFuture异步调用10个其他Rest服务时发生SocketTimeoutException

我有一个带有Spring 4.0.3.RELEASE的Java 8应用程序。从这个应用程序,我将请求异步发送到10个不同的Rest服务。

更新:这10个不同的Rest服务是一个单体应用程序上的10个不同的端点。

代码工作正常,但有时会请求挂起并抛出SocketTimeoutException。如果我在RestTemplate对象上设置了一些超时,则它将在该特定超时之后引发异常。但是,如果我不设置超时,则请求会挂起,并在一段时间后引发相同的异常。我的应用程序调用的服务是使用Node.js编写的,该应用程序的错误如下:

ERROR CATCHED:  ClientError [BadRequestError]: request aborted
at abortIncoming (_http_server.js:492:9)
message: 'request aborted',type: 'request.aborted' 

据我所知,此错误是由于在Node.js应用程序读取请求之前请求被取消而发生的。例如,当您单击Postman的“发送”按钮并立即单击“取消”按钮时。但是,当我一个接一个地同步发送请求时,除了时间没有问题。我不想因性能问题而同步调用这些服务。

Java方面的异常是:

org.springframework.web.client.ResourceaccessException: I/O error on POST request for "SOMEURL":Read time out after 1000 millis; nested exception is java.net.SocketTimeoutException: Read time out after 1000 millis
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:557)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:502)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:330)
at tr.com.ingbank.service.impl.IntentServiceImpl.getIntentResponse(IntentServiceImpl.java:231)
at tr.com.ingbank.service.impl.IntentServiceImpl.access$000(IntentServiceImpl.java:51)
at tr.com.ingbank.service.impl.IntentServiceImpl$1.get(IntentServiceImpl.java:105)
at tr.com.ingbank.service.impl.IntentServiceImpl$1.get(IntentServiceImpl.java:98)
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.net.SocketTimeoutException: Read time out after 1000 millis
at weblogic.socket.NIOSocketMuxer$NIOInputStream.readInternal(NIOSocketMuxer.java:855)
at weblogic.socket.NIOSocketMuxer$NIOInputStream.read(NIOSocketMuxer.java:788)
at weblogic.socket.NIOSocketMuxer$NIOInputStream.read(NIOSocketMuxer.java:771)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
at weblogic.net.http.MessageHeader.isHTTP(MessageHeader.java:310)
at weblogic.net.http.MessageHeader.parseHeader(MessageHeader.java:232)
at weblogic.net.http.HttpClient.parseHTTP(HttpClient.java:549)
at weblogic.net.http.HttpURLConnection.getInputStream(HttpURLConnection.java:639)
at weblogic.net.http.SOAPHttpURLConnection.getInputStream(SOAPHttpURLConnection.java:37)
at weblogic.net.http.HttpURLConnection.getResponseCode(HttpURLConnection.java:1445)
at org.springframework.http.client.SimpleclientHttpResponse.getRawStatusCode(SimpleclientHttpResponse.java:48)
at org.springframework.http.client.AbstractClientHttpResponse.getStatusCode(AbstractClientHttpResponse.java:33)
at org.springframework.web.client.DefaultResponseErrorHandler.getHttpStatusCode(DefaultResponseErrorHandler.java:56)
at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:50)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:542)
... 8 more

我的异步REST调用代码如下:

CompletableFuture<IntentResponse> future = CompletableFuture.supplyAsync(new Supplier<IntentResponse>() {

    @Override
    public IntentResponse get() {

        System.out.println("Calling service asynchronously with botName=" + finalBotName);
        try {
            return getIntentResponse(finalIntentRequest,finalBotName);
        } catch (Exception e) {
            e.printStackTrace();
            // insert error log
            return new IntentResponse();
        }

    }

});

futures.add(future);

此代码块位于for循环内,这是准备所有请求的方式。准备好所有请求之后,我调用 get()方法,该方法将运行所有其余调用,并且 allOf()方法允许我的应用程序等待所有响应。

CompletableFuture<IntentResponse>[] responseFuturesArray = (CompletableFuture<IntentResponse>[]) new CompletableFuture[futures.size()];
futures.toArray(responseFuturesArray);

CompletableFuture<Void> result = CompletableFuture.allOf(responseFuturesArray);

result.get();

for(CompletableFuture<IntentResponse> future : futures){

    intentResponses.add(future.get());

}

异步调用的方法是使用Springframework中的RestTemplate类进行的简单REST调用。如果出现问题,我也可以使用此方法:

private IntentResponse getIntentResponse(IntentRequest intentRequest,String botName) throws Exception {

    String url = appConfigService.getappConfigValueByType(AppConstants.INTERNAL_INTENT_ENGINE_URL);
    String token = appConfigService.getappConfigValueByType(botName);
    url = url + botName;
    String sessionIdWithBotName = intentRequest.getUserId();
    String sessionId = sessionIdWithBotName.split("_").length > 1 ? sessionIdWithBotName.split("_")[1] : sessionIdWithBotName;

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    headers.setaccept(Collections.singletonList(MediaType.APPLICATION_JSON));
    headers.add("Cbot-Token",token);

    long start = System.currentTimeMillis();


    HttpEntity<IntentRequest> request = new HttpEntity<IntentRequest>(intentRequest,headers);
    IntentResponse response = restTemplate.postForObject(url,request,IntentResponse.class);
    response.setBotName(botName);

    long elapsedTime = System.currentTimeMillis() - start;

    // insert log

    return response;
}

我已经处理了2个星期的问题,没有尝试过。我试图编写使用HttpUrlConnection,ExecutorService-newCachedThreadPool,newFixedThreadPool等发送请求的方法,我知道它们之间的区别,但是它们都有相同的错误,并且这些错误没有模式(与请求无关,不是与时间或请求之间的时间间隔有关。)。所有请求都已成功发送并成功接收到响应,或者所有请求都挂起,超时或被调用。任何帮助将不胜感激。

alan0633 回答:ExecutionException-尝试使用CompletableFuture异步调用10个其他Rest服务时发生SocketTimeoutException

暂时没有好的解决方案,如果你有好的解决方案,请发邮件至:iooj@foxmail.com
本文链接:https://www.f2er.com/2942235.html

大家都在问