Scala-finally timeout和Thread.sleep()之间的区别



我有一些异步(ZIO(代码,需要对其进行测试。如果我使用Thread.sleep()创建一个测试部件,它运行良好,并且我总是得到响应:

for {
saved <- database.save(smth)
result <- eventually {
Thread.sleep(20000)
database.search(...) 
}
} yield result

但如果我使用eventually中的timeoutinterval进行了相同的逻辑,那么它永远不会正常工作(我得到了超时(:

for {
saved <- database.save(smth)
result <- eventually(timeout(Span(20, Seconds)), interval(Span(20, Seconds))) {
database.search(...) 
}
} yield result

我不明白为什么timeoutinterval的工作原理与Thread.sleep不同。它应该做完全相同的事情。有人能向我解释一下,并告诉我应该如何更改此代码以不需要使用Thread.sleep()吗?

假设database.search(...)返回ZIO[]对象。

CCD_ 11很可能在第一次尝试后立即成功。

它成功地创建了一个查询数据库的任务。然后在没有任何重试逻辑的情况下查询数据库。

关于如何使其发挥作用:

val search: ZIO[Any, Throwable, String] = ???
val retried: ZIO[Any with Clock, Throwable, Option[String]] = search.retry(Schedule.spaced(Duration.fromMillis(1000))).timeout(Duration.fromMillis(20000))

这样的东西应该行得通。但我相信还有更优雅的解决方案。

@simpadjo的另一个答案解决了"什么";非常简洁。我将添加一些额外的上下文,说明您为什么会看到这种行为。

for {
saved <- database.save(smth)
result <- eventually {
Thread.sleep(20000)
database.search(...) 
}
} yield result

这里混合了三种不同的技术,这引起了一些混乱。

首先是ZIO,它是一个异步编程库,使用自己的自定义运行时和执行模型来执行任务。第二个是eventually,它来自ScalaTest,用于通过有效地轮询值的状态来检查异步计算。第三,还有Thread.sleep,它是一个Java api,它实际上挂起当前线程并阻止任务进行,直到计时器到期。

eventually使用了一种简单的重试机制,根据您使用的是scala标准库中的正常值还是Future而有所不同。基本上,它在块中运行代码,如果抛出,则会休眠当前线程,然后根据一些间隔配置重试,最终超时。值得注意的是,在这种情况下,行为是完全同步的,这意味着只要{}中的值没有抛出异常,它就不会继续重试。

CCD_ 17是一个重载操作,在这种情况下,它有效地阻止了传递给CCD_ 18的功能进行20秒。这意味着当调用database.search时,操作可能已经完成。

第二种变体不同,它立即执行eventually块中的代码,如果它抛出异常,它将根据您提供的间隔/超时逻辑再次尝试。在这种情况下,保存可能尚未完成(如果最终一致,则可能尚未传播(。因为您返回的是一个ZIO,它被设计为而不是抛出,而eventually不理解ZIO,所以它只会返回search尝试,而没有重试逻辑。

公认的答案:

val retried: ZIO[Any with Clock, Throwable, Option[String]] = search.retry(Schedule.spaced(Duration.fromMillis(1000))).timeout(Duration.fromMillis(20000))

工作是因为retrytimeout使用内置的ZIO运算符,确实了解如何将retrytimeout实际设置为ZIO。这意味着如果搜索失败,retry将处理它,直到它成功。

相关内容

  • 没有找到相关文章

最新更新