我对scala很新,所以要温柔!
我正在尝试创建一个"逻辑事务",这是一个代码示例:
val f1:Future[Int] = dao.insertIntoDB
f1.flatmap{
x => {
val f2 = sendHttpRequestFuture
f.onFailure{
case t => dao.revertDbChangeFuture
}
}
f1.onFailure{
logger.error("error)
}
所以我认为将会发生外部onFailure,然后内部onFailure。
问题是onFailure返回Unit,所以将未来放在onFailure中感觉很奇怪,我不确定处理这种用例的正确方法是什么。
我基本上需要还原我的更改,并且还原操作是异步的。
你能建议吗? 谢谢!答案 0 :(得分:1)
你不应该使用revertDbChangeFuture
,因为一旦你有了这个未来,它通常意味着你已经触发了基础计算,即你已经恢复了数据库的变化,无论结果如何插入物。
相反,您应该添加方法,以便在onFailure
回调中恢复数据库更改:
insertIntoDBFuture.onFailure {
case t => revertDbChange()
}
val f1 = insertIntoDBFuture.flatmap(sendHttpRequestFuture(_))
f1.onFailure{
case t => logger.error("error", t)
}
f1
如果flatMap
失败,<{1>} val f1 = insertIntoDBFuture.flatmap(sendHttpRequestFuture(_))
中的insertIntoDBFuture
将无法执行,因此您不必担心这一点。相反,f1
的结果将是同一个失败的未来,因此如果没有错误发生,您将记录insertIntoDBFuture
或sendHttpRequestFuture
的错误 - 或者没有错误。
答案 1 :(得分:1)
使用此示例播放。 它显示了一切如何运作。 实际上,因为我看到你已经实现了。
您可以修改两个变量job1Fail
和job2Fail
。
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
object FutFut extends App {
val f1: Future[Int] = Future {
doJob
}
val job1Fail = false
val job2Fail = true
def doJob() = {
if (job1Fail) sys.error("Failed to do job") else {
println("job 1 done")
1
}
}
def doOtherJob() {
if (job2Fail) sys.error("Failed to do other job") else {
println("other job done")
}
}
def revertingAll() {
println("reverting all")
}
f1.flatMap {
x => {
val f2 = Future {
doOtherJob()
}
f2.onFailure {
case t => revertingAll()
}
f2
}
}
f1.onFailure {
case t => println("f1 failed")
}
Thread.sleep(1000)
}
结果如下:
db job failed - &gt;输出消息f1失败。没有回复。
db job ok - &gt;调用平面地图 - &gt; http失败 - &gt; revert invoked - &gt; f1不会失败
db job ok - &gt;调用平面地图 - &gt; http ok - &gt;一切都好 - &gt;没有还原 - &gt;没有失败:)
这几乎都是用例。
答案 2 :(得分:0)
在这种情况下,您应该使用recoverWith
API,这样您就可以将失败的未来转变为另一个未来:
f2.recoverWith({
case NonFatal(_) => dao.revertDbChangeFuture
})
这将为您提供针对撤消操作的Future。