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

Spring Boot集成Couchbase集成测试超时问题求助

Couchbase集成测试超时问题排查与解决

问题背景

具备丰富Spring Boot开发经验,刚接触Couchbase,编写Repository、实体类、测试用例及配置后,执行测试时触发AmbiguousTimeoutException,错误详情包含COLLECTION_MAP_REFRESH_IN_PROGRESS提示。

代码与配置详情

Repository代码

import entity.Building;
import org.springframework.data.couchbase.repository.Collection;
import org.springframework.data.couchbase.repository.CouchbaseRepository;

@Collection("buildings")
public interface BuildingRepository extends CouchbaseRepository<Building, String> {
    
}

Building实体类代码

@Document
public class Building {

    @Id
    @GeneratedValue(strategy = GenerationStrategy.UNIQUE)
    private String id;

    @Field
    @NotNull
    private String erf;
    
    @Field
    @NotNull
    private String name;
    
    @Field
    @NotNull
    private Address address;

    @CreatedBy
    private String creator;

    @LastModifiedBy
    private String lastModifiedBy;

    @LastModifiedDate
    private LocalDateTime lastModification;

    @CreatedDate
    private LocalDateTime creationDate;
    
    @Version
    private long version;
}

测试用例代码

@SpringBootTest
@Testcontainers
@ActiveProfiles({"test"})
@AutoConfigureMockMvc
public class RetrieveBuildingTest {
    @Container
    private static final CouchbaseContainer COUCHBASE = new CouchbaseContainer(
            DockerImageName.parse("couchbase/server:7.1.2")).withBucket(new BucketDefinition("buildings").withPrimaryIndex(true));

    @Autowired
    private MockMvc mvc;

    @Test
    public void testLifecycleForBuildings() throws Exception {
        final ClassPathResource resource = new ClassPathResource("payloads/successful-create-building.json");
        final String payload = Files.readString(Path.of(resource.getURI()));

        // save
        mvc.perform(post("/building")
                .accept(MediaType.APPLICATION_JSON)
                .contentType(MediaType.APPLICATION_JSON)
                .content(payload))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.name", is("Knightsbridge Mansion")));
        
        // retrieval all
        
        mvc.perform(get("/building"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.totalElements", is(1)));
        
        // retrieve specific building by id
    }

    @DynamicPropertySource
    public static void register(final DynamicPropertyRegistry register) {
        register.add("spring.couchbase.connection-string", COUCHBASE::getConnectionString);
        register.add("spring.couchbase.username", COUCHBASE::getUsername);
        register.add("spring.couchbase.password", COUCHBASE::getPassword);
    }
}

application.properties配置

spring.data.couchbase.bucket-name=buildings
spring.couchbase.env.timeouts.connect=30
spring.couchbase.env.timeouts.key-value-durable=30

核心错误信息

Caused by: com.couchbase.client.core.error.AmbiguousTimeoutException: InsertRequest, Reason: TIMEOUT {"cancelled":true,"completed":true,"coreId":"0xf0d3d25700000001","idempotent":false,"lastChannelId":"F0D3D25700000001/0000000058CD068A","lastDispatchedFrom":"127.0.0.1:38858","lastDispatchedTo":"localhost:49158","reason":"TIMEOUT","requestId":5,"requestType":"InsertRequest","retried":14,"retryReasons":["COLLECTION_MAP_REFRESH_IN_PROGRESS"],"service":{"bucket":"buildings","collection":"buildings","documentId":"54b991d2-fa8b-41eb-9b1e-d5519914e964","opaque":"0x15","scope":"_default","type":"kv","vbucket":233},"timeoutMs":2500,"timings":{"encodingMicros":5785,"totalMicros":2512314}}

解决方案

1. 确保目标Collection存在

报错中的COLLECTION_MAP_REFRESH_IN_PROGRESS说明客户端无法找到指定的buildings集合。Couchbase 7.x创建Bucket后,默认仅存在_default集合,不会自动生成自定义集合。

两种解决方式任选其一:

  • 删除Repository上的@Collection("buildings")注解,使用默认的_default集合。
  • 在测试容器初始化时主动创建buildings集合,修改容器配置:
    @Container
    private static final CouchbaseContainer COUCHBASE = new CouchbaseContainer(
            DockerImageName.parse("couchbase/server:7.1.2"))
            .withBucket(new BucketDefinition("buildings").withPrimaryIndex(true))
            .withCommand("/bin/sh", "-c", 
                "/entrypoint.sh couchbase-server & " +
                "sleep 30 && " +
                "couchbase-cli collection-manage --cluster localhost:8091 --username Administrator --password password --bucket buildings --create-collection _default.buildings && " +
                "wait");
    
    注意:需保持命令中的用户名、密码与测试容器默认值(Administrator/password)一致,若有自定义配置需同步修改。

2. 修正超时配置的单位

Spring Boot中Couchbase的超时属性单位为毫秒,当前配置的30仅代表30毫秒,远不足以完成集合元数据刷新和数据插入操作。更新application.properties:

spring.data.couchbase.bucket-name=buildings
# 连接超时设为30秒
spring.couchbase.env.timeouts.connect=30000
# KV操作超时设为10秒
spring.couchbase.env.timeouts.key-value=10000
spring.couchbase.env.timeouts.key-value-durable=10000

3. 等待Bucket与集合完全就绪

测试容器启动后,Bucket和集合需要时间完成初始化,添加等待逻辑确保服务就绪:
在测试类中新增@BeforeAll方法:

@BeforeAll
static void setup() {
    COUCHBASE.start();
    // 等待Bucket就绪
    COUCHBASE.waitForBucket("buildings");
    // 额外等待集合元数据同步
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}

4. 验证主索引状态

尽管测试容器配置了withPrimaryIndex(true),但索引可能未完全生效。可延长初始化等待时间,或在测试中添加索引可用性检查,确保主索引正常工作。

总结

核心问题是自定义集合未创建导致客户端反复刷新元数据,最终触发超时。结合调整超时配置、确保资源就绪,即可解决测试超时问题。属性配置完全满足需求,无需使用AbstractCouchbaseConfiguration。

内容的提问来源于stack exchange,提问作者user3465651

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 21:25:24