Spring Boot从3.1.7升级到3.2.2后WebClient超时异常求助
Spring Boot 3.2.2升级后WebClient超时问题
问题现象
我们团队使用Spring WebClient与API交互,将Spring依赖从3.1.7升级到3.2.2后,出现以下超时错误,导致应用无法正常运行:
java.util.concurrent.TimeoutException: Did not observe any item or terminal signal within 240000ms in 'peekTerminal' (and no fallback has been configured)
WebClient Bean配置
@Bean() WebClient webClient() { return WebClient .builder() .clientConnector( new ReactorClientHttpConnector( HttpClient .create() .wiretap(true) ) ) .baseUrl("API URL") .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString()) .build(); }
WebClient调用代码
webClient .method(HttpMethod.POST) .bodyValue([POJO class]) .retrieve() .bodyToMono([POJO class]) .doOnError(exception -> log the exception) .doOnSuccess(response-> process the response) .timeout(Duration.ofMinutes(4)) .block();
排查背景
- 预期从3.1.7升级到3.2.2不会破坏WebClient实现
- 目标API未做任何更改
- 应用内其他WebClient代码也未改动
- 查看了Spring Boot 3.2.1的发布说明,未找到问题原因
Maven pom.xml配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>a</groupId> <artifactId>b</artifactId> <version>1.0.0</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.release>21</java.release> <spring-boot.version>3.2.2</spring-boot.version> <maven-clean-plugin.version>3.3.1</maven-clean-plugin.version> <maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version> <maven-deploy-plugin.version>3.1.1</maven-deploy-plugin.version> <maven-failsafe-plugin.version>3.1.2</maven-failsafe-plugin.version> <maven-install-plugin.version>3.1.1</maven-install-plugin.version> <maven-resources-plugin.version>3.3.1</maven-resources-plugin.version> <maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version> <maven-verifier-plugin.version>1.1</maven-verifier-plugin.version> <maven-source-plugin.version>3.3.0</maven-source-plugin.version> <maven-dependency-plugin.version>3.6.0</maven-dependency-plugin.version> <maven-enforcer-plugin.version>3.4.1</maven-enforcer-plugin.version> <dependency-check-maven.version>8.4.0</dependency-check-maven.version> <versions-maven-plugin.version>2.16.1</versions-maven-plugin.version> <springdoc.version>2.3.0</springdoc.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jersey</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>${springdoc.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-clean-plugin</artifactId> <version>${maven-clean-plugin.version}</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven-compiler-plugin.version}</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>${maven-dependency-plugin.version}</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>${maven-enforcer-plugin.version}</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>${maven-failsafe-plugin.version}</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>${maven-resources-plugin.version}</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-install-plugin</artifactId> <version>${maven-install-plugin.version}</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>${maven-source-plugin.version}</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>${maven-surefire-plugin.version}</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-verifier-plugin</artifactId> <version>${maven-verifier-plugin.version}</version> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> </plugin> <plugin> <groupId>org.owasp</groupId> <artifactId>dependency-check-maven</artifactId> <version>${dependency-check-maven.version}</version> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>versions-maven-plugin</artifactId> <version>${versions-maven-plugin.version}</version> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <release>${java.release}</release> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>A</mainClass> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.owasp</groupId> <artifactId>dependency-check-maven</artifactId> <configuration> <failBuildOnCVSS>10</failBuildOnCVSS> </configuration> <executions> <execution> <goals> <goal>check</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <executions> <execution> <id>enforce-java</id> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <requireJavaVersion> <version>[21,)</version> </requireJavaVersion> </rules> </configuration> </execution> <execution> <id>enforce-maven</id> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <requireMavenVersion> <version>[3.6.3,)</version> </requireMavenVersion> </rules> </configuration> </execution> <execution> <id>no-duplicate-declared-dependencies</id> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <banDuplicatePomDependencyVersions/> </rules> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>versions-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
解决方案
1. 显式配置Reactor Netty连接池
Spring Boot 3.2.x升级后,Reactor Netty默认连接池行为可能调整,未指定参数时高并发场景易出现连接耗尽。修改WebClient配置添加连接池参数:
@Bean WebClient webClient() { HttpClient httpClient = HttpClient.create() .wiretap(true) .tcpConfiguration(tcpClient -> tcpClient .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000) .connectionPool(ConnectionPoolSpec.builder() .maxConnections(100) .pendingAcquireTimeout(Duration.ofSeconds(60)) .build()) ); return WebClient.builder() .clientConnector(new ReactorClientHttpConnector(httpClient)) .baseUrl("API URL") .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString()) .build(); }
2. 调整超时策略层级
将超时配置提前到响应处理阶段,并在HttpClient层面添加全局响应超时,避免局部超时覆盖不全:
// HttpClient层面添加全局响应超时 HttpClient httpClient = HttpClient.create() .wiretap(true) .responseTimeout(Duration.ofMinutes(4)) // ... 其他连接池配置
// 调用时调整超时位置 webClient .method(HttpMethod.POST) .bodyValue([POJO class]) .retrieve() .bodyToMono([POJO class]) .timeout(Duration.ofMinutes(4)) .doOnError(exception -> log the exception) .doOnSuccess(response-> process the response) .block();
3. 排查Web框架冲突
pom.xml同时引入spring-boot-starter-jersey和spring-boot-starter-webflux,两者均为Web框架,可能存在上下文初始化或依赖冲突。若无需Jersey,直接移除该依赖;若必须保留,需确保Spring Boot正确处理两者的上下文隔离。
4. 开启详细日志定位问题
添加Reactor Netty的DEBUG日志,追踪请求的连接、发送、响应全生命周期,确认超时具体原因:
logging.level.io.netty=DEBUG logging.level.reactor.netty=DEBUG
内容的提问来源于stack exchange,提问作者Dominique Claes
相关产品推荐
相关产品推荐

