我最近发现一个与Monix Task
合作时无法完全理解的案例:
有两个函数(在队列消息处理程序中):
def handle(msg: RollbackMsg): Task[Unit] = {
logger.info(s"Attempting to rollback transaction ${msg.lockId}")
Task.defer(doRollback(msg)).onErrorRestart(5).foreachL { _ =>
logger.info(s"Transaction ${msg.lockId} rolled back")
}
}
private def doRollback(msg: RollbackMsg): Task[Unit] =
(for {
originalLock <- findOrigLock(msg.lockId)
existingClearanceOpt <- findExistingClearance(originalLock)
_ <- clearLock(originalLock, existingClearanceOpt)
} yield ()).transact(xa)
doRollback
的理解力内部是一组doobie个调用,它们返回ConnectionIO[_]
monad,然后在其上运行transact
,将构图变成Monix Task
。
现在,如handle
函数所示,我希望整个过程在失败的情况下重试5次。神秘的部分是这个简单的调用:
doRollback(msg).onErrorRestart(5)
并不会真正在异常上重新启动操作(已在测试中验证)。为了获得这种重试行为,我必须将其显式包装在Task.defer
中,或者以任何其他方式将其包含在Task
“上下文”中。
这是我没有完全明白的要点:为什么会这样? doRollback
已经给了我Task
实例,所以我应该可以在它上调用onErrorRestart
,不是吗?如果不是这种情况,如何确定从“某处”获得的Task
实例是否可以重新启动?
我在这里想念什么?