把未来放在OnFailure中

时间:2015-11-02 17:48:33

标签: scala future

我对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中感觉很奇怪,我不确定处理这种用例的正确方法是什么。

我基本上需要还原我的更改,并且还原操作是异步的。

你能建议吗? 谢谢!

3 个答案:

答案 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的结果将是同一个失败的未来,因此如果没有错误发生,您将记录insertIntoDBFuturesendHttpRequestFuture的错误 - 或者没有错误。

答案 1 :(得分:1)

使用此示例播放。 它显示了一切如何运作。 实际上,因为我看到你已经实现了。

您可以修改两个变量job1Failjob2Fail

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。