使用 Mutiny 实现重试逻辑

Implement retry logic with Mutiny

我刚开始学习 Mutiny,我需要实现重试逻辑。

我有这个代码:

fun main() {
    getResult()
        .onFailure().invoke { t -> println("Got error: $t") }
        .onFailure().retry().atMost(2)
        .subscribe().with(
            { result -> println(result) },
            { t -> t.printStackTrace() }
        )
}

fun getResult(): Uni<String?> {
    println("Preparing result...")

    return Uni.createFrom().failure(Exception("Some error happened"))
}

因此,getResult() 是一个可能会出现异常的函数,需要在失败时多次调用。

当我运行这个程序时,是这样的:

Preparing result...
Got error: java.lang.Exception: Some error happened
Got error: java.lang.Exception: Some error happened
Got error: java.lang.Exception: Some error happened
java.lang.Exception: Some error happened
    at MainKt.getResult(Main.kt:16)
    at MainKt.main(Main.kt:4)

值得注意的是,getResult() 函数只被调用一次,而 onFailure() 阶段实际上执行了三次。

Mutiny 是否可以帮助我在每次失败时执行 getResult() 功能?我当然可以用一个简单的循环来实现它,但我觉得 Mutiny 应该已经有这样的东西了。

很遗憾,我没有在文档中找到合适的内容。

您在 getResult 中的 Uni 是使用“立即”项目创建的,该项目被缓存并且不再计算。

使用 Uni.createFrom().failure(() -> Exception("Some error happened"))

在本例中,它是一个供应商,因此它不会被缓存,但会在每次尝试时调用。

因此,正确的解决方案实际上是使用这样的 Uni.deferred() 方法:

fun main() {
    Uni.createFrom().deferred { getResult() }
        .onFailure().invoke { t -> println("Got error: $t") }
        .onFailure().retry().atMost(2)
        .subscribe().with(
            { result -> println(result) },
            { t -> t.printStackTrace() }
        )
}

感谢 Boris the Spider 建议使用 deferred(),感谢 Clement,他阐明了空值的用法。

最初,我误解了 deferred() 文档,认为它不允许 return 一个空值,但实际上 Supplier 到 return 一个 Uni 为空:

Uni.createFrom.deferred { Uni.createFrom().nullItem() }

文档真正禁止的是 return 空而不是 Uni:

Uni.createFrom().deferred { null }