
Mutiny 的 onFailure() 并非单个操作符,而是一组用于声明性定义错误处理逻辑的入口点;其设计初衷是通过多次调用 onFailure() 实现清晰、可读性强的错误处理链,而非强制串联成单一流畅链。
mutiny 的 `onfailure()` 并非单个操作符,而是一组用于声明性定义错误处理逻辑的入口点;其设计初衷是通过多次调用 `onfailure()` 实现清晰、可读性强的错误处理链,而非强制串联成单一流畅链。
在 Mutiny 中,Uni<t></t> 的错误处理并非基于“流式链式调用”(如 map().filter().onFailure().retry() 这类线性结构),而是采用分组式错误响应建模:每次调用 .onFailure() 都会开启一个独立的错误处理分支,作用于当前 Uni 的异常路径,并返回一个 UniOnFailure<t></t> 对象——该对象仅提供针对“失败场景”的专属操作(如 invoke()、retry()、recoverWithItem() 等),执行完毕后自动回归原始 Uni<t></t> 类型,以便继续主流程或开启下一轮错误处理。
因此,你最初的写法不仅是合法的,而且是 符合 Mutiny 设计哲学的最佳实践:
someUni
.onFailure().invoke(e -> log.info("Error occurred: {}", e.getMessage()))
.onFailure().retry()
.withBackOff(Duration.ofMillis(100), Duration.ofSeconds(5))
.atMost(5)
.onFailure().invoke(() -> log.info("Retries exhausted, giving up."))
.onFailure().recoverWithItem(Response.ok().build());✅ 优点说明:
-
语义明确:每一处
.onFailure()清晰标识“此处开始定义某类失败行为”,避免嵌套或回调地狱; - 职责分离:日志、重试、兜底恢复各自独立配置,互不干扰;
-
类型安全:
UniOnFailure<t></t>仅暴露与错误处理相关的 API,防止误用成功路径操作符(如map)。
⚠️ 注意事项:
- 不要试图用
.onFailure().invoke(...).retry().recoverWithItem(...)将多个操作挤在一次onFailure()调用中——invoke()返回的是Uni<t></t>,后续.retry()将作用于 成功值,而非错误流,导致逻辑失效; -
retry()必须紧跟在.onFailure()之后调用,否则它将作用于上游Uni的正常发射,而非错误重试; - 若需条件化重试(例如仅对特定异常重试),可配合
.onFailure(Predicate<throwable>)</throwable>使用,如.onFailure(e -> e instanceof IOException).retry().atMost(3)。
? 小结:Mutiny 有意放弃“单链式错误处理”的表面简洁,换取更强的可读性与行为确定性。与其追求语法上的“链得更短”,不如拥抱其分组式设计——每一次 .onFailure() 都是你对错误契约的一次清晰声明。

















