当前位置: 首页 > 知识库问答 >
问题:

无法处理未来失败的异常

汲利
2023-03-14

我希望下面的代码在其中一个方法<code>callfuture1()</code>或<code>callfuture2()</code>抛出异常时返回自定义消息。我的理解是,如果任何一个未来失败,f都将是失败的未来。

但是,当 callfuture1 引发异常时。f.onFailure 不执行。相反,我看到调用堆栈停止在 callFuture1() 中的代码行,其中发生了异常并返回了标准内部错误。为什么会这样?

val f = for {
 x <- callfuture1()
 y <- callfuture2()
} yield y

f.onFailure {
 //send an internalserver error with some custom message
}

f.map {
 //send data back
}

====更新====

我从响应中看到,潜在的问题是异常被抛出未来,因此我的代码无法捕获失败的未来。所以我改变了代码,使得异常只发生在将来。我仍然无法解释我所看到的行为。(我想知道它是否与Play框架有任何关系。

def controllerfunction(id: String) = Action.async{

  val f = for{
    x <- callfuture1(id)
    y <- callfuture2(x)
  } yield y

  y.onFailure{case t => 
    println("This gets printed");
    Ok("shit happened, but i am still ok")}

  y.map{resp:String => Ok(resp)}

}

def callfuture1(id: String):Future[Obj1] = {
  for {
    val1 <- callfuture1.1(id)
    val2 <- callfuture1.2(val1)
  } yield val2
}

def callfuture1.2:Future[Obj3] = Future{
  thrown new Exception("TEST ME");
}

def callfuture 1.1:Future[Obj4] = {...}
def callfuture2: Future[String] = {....}

期待。方法callfuture1.2在未来抛出一个异常,所以我的期望是onFailure应该被执行,(它确实被执行了),返回的响应应该是“Shit happened,但我仍然没事”

实际情况 Play框架返回 InternalServerError,我在控制台上看到错误堆栈。我看到 printlin(“This get print”) 正在执行。

无法理解发生了什么。有什么见解吗?

====更新2=====

我验证了只有在play框架的控制器内部调用时才会发生此问题(我正在使用play 2.5)。作为一个独立的 scala 程序,一切按预期工作。我相信播放错误处理会捕获未处理的异常并打印堆栈跟踪。我认为这应该只发生在开发环境中。

共有2个答案

杜俊爽
2023-03-14

似乎在< code>callfuture1()中,您没有像

def callfuture1(): Future[?] = Future {
  val x = ...
  x
}

但你的代码似乎是

def callfuture1(): Future[?] = {
  val x = ... // some error happen here
  Future(x)
}

因为它在未来之外,所以你的错误会直接出现在你的程序代码

寿意远
2023-03-14

如果call Future1抛出“未来之外”,就会发生这种情况。您的理解被分解为:

val f = callfuture1.flatMap{ x =>
  callfuture2.map{ y =>
    y
  }
}

如果<code>callfuture2</code>立即抛出(与返回失败的未来相反),您仍将以失败的未来告终,因为<code>callfuture2</code>在<code>future内部调用。flatMap,它捕获异常并将其转化为失败的未来(与<code>Future.map</code>相同)。

call Future1的情况不同:如果它立即抛出,则没有封闭的Future.mapFuture.flatMap将其变成失败的未来。

一般来说,您应该尽量避免使用返回Future并且也可以抛出错误的方法。这意味着如果call Future1执行任何可以抛出的操作,它应该会捕获它并在您随后返回的失败未来中打开异常。

更新:关于你的更新,关于你如何期望“狗屎发生了,但我仍然很好”被返回:

正如马頔在评论中暗示的那样,< code>Future.onFailure只能用于副作用。未来是不可变的。如果你想从一个失败的异常中恢复,没有办法修改原来的(失败的)未来,你实际上能做的就是把它转换成一个新的未来。看看< code>Future.recover。它做的正是你所需要的,即它允许通过匹配失败的结果(如果有的话)并将其转换为成功的未来来转换输入的未来。这相当于一个捕捉条款,但对期货来说。具体来说,你真正想做的是这样的:

def controllerfunction(id: String) = Action.async{
  val f = for{
    x <- callfuture1(id)
    y <- callfuture2(x)
  } yield y

  f.map{ resp: String => 
    Ok(resp)
  }.recover{
    case t: Throwable => 
      println("This gets printed");
      Ok("shit happened, but i am still ok")
  }
}
 类似资料:
  • 给定的带有Selenium的Robot框架已准备好在Chrome中执行测试它工作了很长时间当我现在用Jenkins在Robot框架中执行测试时,我收到一个错误“02:05:44 WebDriverException:消息:未知错误:无法处理扩展#1 02:05:44from未知错误:CRX验证失败:3” 升级后的Chrome和驱动程序可能无法使用旧的插件吗?我该怎么解决这个问题?升级插件?升级驱动

  • 在Scala中,未来可能会失败,这可以异步发现: 你将如何“翻译”成Clojure?我的阅读让我相信Clojure未来/promise模型没有Scala的强大,你不能就这样抓住失败。那么该怎么办呢? Scala的未来永远不需要被问到它的价值——当它好并准备好时,它会告诉你发生了什么(包括它是否失败——这是这个问题的关键)。这就是我所说的“异步”的意思。Scala的未来可以处于三种可能的状态之一——

  • 异常严重:Servlet。路径为[z2]的上下文中servlet[dispatcher]的service()引发异常[请求处理失败;嵌套异常为org.springframework.dao.DataIntegrityViolationException:not null属性引用null或瞬时值:com.spring.entity.Product.cd;嵌套异常为org.hibernate.Prop

  • 当我尝试连接到Oracle数据库时,出现了以下问题。 有例外 此reportMapper.xml

  • 问题内容: 我正在开发一个Android应用,该应用必须将json格式的Java对象保存到SQLite数据库中。我为此操作编写了代码,然后他们必须提取Json对象并将其重新转换为Java对象。当我尝试调用将json对象反序列化为字符串的方法时,我在Android Studio中发现此错误: 当我尝试捕获程序运行但不反序列化json对象时。 这是该方法的代码: 你能帮我吗? 问题答案: 是的,您需要

  • 问题内容: 当我运行程序时,出现此错误: 未处理无效的强制转换异常 这是用于填充数据库的表单的一部分,而Visual Studio会将int cast标记为错误 问题答案: 我 强烈 怀疑,您用错误的方式参数化了您的零件。您至少需要弄清楚您试图获取包含那些字符串的值。喜欢; 不要使用尽可能多的东西。有时它 可能会 产生意外和令人惊讶的结果 。使用方法重载来指定参数类型及其大小。 也可以使用语句自动