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

Quarkus中使用Mutiny重试策略后Uni失败订阅未执行问题

问题分析与解决方案

这个问题我之前也踩过坑,核心原因是你没处理Mutiny异步操作的等待逻辑!你的测试方法是同步执行的,当主线程跑到assertTrue(executed.get())这行时,带延迟的重试流程根本还没走完,失败订阅自然还没被触发,所以断言必然失败。

为什么会这样?

Mutiny的重试机制(尤其是带withBackOff的)是异步执行的,每次失败后会等待指定的延迟时间再重试。你的测试代码没有任何阻塞等待的逻辑,主线程直接跑完断言,这时候5次重试(加上每次1秒左右的延迟)还在后台异步执行,executed变量自然还是false。

怎么解决?

有两种常用的方式让测试等待异步流程完成:

方式1:用await()阻塞主线程直到Uni完成

给订阅后的Uni添加等待逻辑,确保所有重试完成后再执行断言:

@Test
void mutinySubscriptionNotCalledAfterRetry() {
    final AtomicBoolean executed = new AtomicBoolean(false);
    Uni.createFrom().item(this::error)
        .onFailure()
        .retry()
        .withBackOff(Duration.ofSeconds(1)).withJitter(0.2)
        .atMost(5)
        .subscribe()
        .with(success -> fail(), failure -> executed.set(true))
        .await().atMost(Duration.ofSeconds(10)); // 预留足够时间让5次重试完成
    assertTrue(executed.get());
}

方式2:用AssertSubscriber更优雅地测试Mutiny流

Mutiny提供了专门的测试订阅者AssertSubscriber,可以更方便地验证异步流的结果:

@Test
void mutinySubscriptionNotCalledAfterRetry() {
    // 创建测试订阅者并订阅流
    AssertSubscriber<Boolean> subscriber = Uni.createFrom().item(this::error)
        .onFailure()
        .retry()
        .withBackOff(Duration.ofSeconds(1)).withJitter(0.2)
        .atMost(5)
        .subscribe().withSubscriber(AssertSubscriber.create());

    // 等待流失败,并验证失败类型
    subscriber.awaitFailure(Duration.ofSeconds(10));
    assertTrue(subscriber.getFailure() instanceof RuntimeException);
}

补充说明

你提到的Clement的示例代码,大概率是在异步运行环境(比如Quarkus应用内部)中执行的,或者示例中隐含了等待逻辑,所以能正常触发失败订阅。而你的单元测试是同步执行的,必须显式处理异步等待的问题。

内容的提问来源于stack exchange,提问作者Rafa S.R.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 23:47:37