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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 23:33:09