You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何延长AsyncRestTemplate调用异步服务的超时时间?

AsyncRestTemplate调用长耗时异步服务时出现503错误,如何延长客户端超时时间?

问题描述

我用Spring框架开发了异步Web服务,同时用AsyncRestTemplate创建客户端调用这些服务。getForEntity方法返回ListenableFuture<ResponseEntity<T>>,正常情况下运行没问题,但当服务处理耗时较长时,isDone()会提前返回true,调用get()时还会抛出503错误:

"timestamp": "2018-05-29T22:42:26.978+0000", "status": 500, "error": "Internal Server Error", "message": "java.util.concurrent.ExecutionException: org.springframework.web.client.HttpServerErrorException: 503 null", "path": "/client/result"

我尝试在application.properties里设置spring.mvc.async.request-timeout=500000,但完全没效果。

服务端代码

配置类

@Configuration 
@EnableAsync 
public class ConfigurationClass { 
    @Bean 
    public Executor threadPoolTaskExecutor() { 
        return new ThreadPoolTaskExecutor(); 
    } 
}

控制器类

@RestController 
@RequestMapping("/server") 
public class ControllerClass { 
    @GetMapping("/start") 
    @Async 
    public CompletableFuture<String> callService() throws InterruptedException{ 
        Thread.sleep(100000L); 
        return CompletableFuture.completedFuture("OK"); 
    } 
}

客户端代码

@RestController 
@RequestMapping("/client") 
public class ControllerClass { 
    private ListenableFuture<ResponseEntity<String>> entity; 

    @GetMapping("/start") 
    @Async 
    public void callService() throws InterruptedException { 
        AsyncRestTemplate restTemplate = new AsyncRestTemplate(); 
        entity = restTemplate.getForEntity("http://localhost:8080/server/start", String.class); 
    } 

    @GetMapping("/state") 
    public boolean getState() { 
        try { 
            return entity.isDone(); 
        } catch (Exception e) { 
            throw new RuntimeException(e); 
        } 
    } 

    @GetMapping("/result") 
    public ResponseEntity<String> getResult() { 
        try { 
            return entity.get(); 
        } catch (Exception e) { 
            throw new RuntimeException(e); 
        } 
    } 
}

我希望客户端能等待足够长的时间,直到服务端返回结果,请问该怎么解决?


解决方案

首先得明确一个关键区别:你设置的spring.mvc.async.request-timeout是服务端处理异步请求的超时时间,和客户端AsyncRestTemplate的请求超时完全没关系,所以这个配置对你的问题起不到作用。要解决503错误,咱们得给客户端的AsyncRestTemplate单独配置超时参数。

1. 给AsyncRestTemplate配置自定义的请求工厂

AsyncRestTemplate默认用的SimpleClientHttpRequestFactory有默认的超时限制,咱们手动修改它的连接和读取超时:

先创建一个配置类,把AsyncRestTemplate做成Bean并配置超时:

@Configuration
public class AsyncRestTemplateConfig {
    @Bean
    public AsyncRestTemplate asyncRestTemplate() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        // 连接超时设置为5秒(根据你的网络情况调整)
        factory.setConnectTimeout(5000);
        // 读取超时设置为500秒(比你服务端的100秒处理时间长就行)
        factory.setReadTimeout(500000);
        return new AsyncRestTemplate(factory);
    }
}

然后在客户端控制器里注入这个Bean,不要每次都new一个AsyncRestTemplate:

@RestController 
@RequestMapping("/client") 
public class ControllerClass { 
    private ListenableFuture<ResponseEntity<String>> entity;
    private final AsyncRestTemplate asyncRestTemplate;

    // 构造注入配置好的AsyncRestTemplate
    public ControllerClass(AsyncRestTemplate asyncRestTemplate) {
        this.asyncRestTemplate = asyncRestTemplate;
    }

    @GetMapping("/start") 
    @Async 
    public void callService() throws InterruptedException { 
        entity = asyncRestTemplate.getForEntity("http://localhost:8080/server/start", String.class); 
    }

    // state和result方法保持不变...
}

2. 可选:用真正的异步HTTP客户端(Apache HttpClient)

如果你的项目里已经依赖了Apache HttpClient,推荐用HttpComponentsAsyncClientHttpRequestFactory,这是真正的异步实现,性能更好:

@Bean
public AsyncRestTemplate asyncRestTemplate() {
    HttpComponentsAsyncClientHttpRequestFactory factory = new HttpComponentsAsyncClientHttpRequestFactory();
    RequestConfig requestConfig = RequestConfig.custom()
            .setConnectTimeout(5000)
            .setSocketTimeout(500000)
            .build();
    CloseableHttpAsyncClient client = HttpAsyncClients.custom()
            .setDefaultRequestConfig(requestConfig)
            .build();
    factory.setHttpAsyncClient(client);
    return new AsyncRestTemplate(factory);
}

3. 确保服务端的异步超时也足够长

虽然你设置的spring.mvc.async.request-timeout=500000是服务端的配置,但这个值也要大于你的服务端处理时间(100秒),它控制的是Spring MVC等待@Async方法返回的CompletableFuture完成的最长时间,避免服务端提前断开连接。

4. 优化客户端的get()调用

你现在用的entity.get()是无参的,会无限等待,但如果前面的超时配置没覆盖到,还是可能出问题。可以用带超时参数的get()方法主动控制等待时间:

@GetMapping("/result") 
public ResponseEntity<String> getResult() { 
    try { 
        // 等待500秒,和前面的读取超时保持一致
        return entity.get(500, TimeUnit.SECONDS); 
    } catch (Exception e) { 
        throw new RuntimeException(e); 
    } 
}

内容的提问来源于stack exchange,提问作者J. Abel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:11:13