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.
相关产品推荐
相关产品推荐

