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

Scala的错误处理:理解的未来

欧阳洲
2023-03-14

我想在我的play scala Web应用程序中进行错误处理。

我的应用程序与数据库对话以获取一些行,它遵循以下流程。

    < li >首先调用数据库以获取一些数据 < li >使用第一次调用中的数据从数据库中提取其他数据 < li >使用从最近两次db调用中收到的数据形成响应。

下面是我的伪代码。

 def getResponse(name: String)
      (implicit ctxt: ExecutionContext): Future[Response] = {
    for {
        future1 <- callFuture1(name)
        future2 <- callFuture2(future1.data)
        future3 <- callFuture3(future1.data, future2.data)
    }  yield future3
  }

以上理解中的每一个方法都返回一个未来,这些方法的签名如下。

private def callFuture1(name: String)
  (implicit ctxt: ExecutionContext): Future[SomeType1] {...}

private def callFuture2(keywords: List[String])
  (implicit ctxt: ExecutionContext): Future[SomeType2] {...}

private def callFuture3(data: List[SomeType3], counts: List[Int])
  (implicit ctxt: ExecutionContext): Future[Response] {...}

在以下情况下,我该如何进行错误/故障处理

    < li >当callFuture1无法从数据库获取数据时。我想用错误消息返回一个适当的错误响应。因为callFuture2只在callFuture1之后执行。如果callFuture1失败/出错,我不想执行callFuture2,而是希望立即返回错误消息。(callFuture2和callFuture3也是如此)

--编辑--

当任何一个调用Future失败并且不能继续后续的future调用时,我试图从getResponse()方法返回一个适当的错误响应。

根据彼得·尼扬的回答,我尝试了以下方法,但出现了运行时错误。。

 def getResponse(name: String)
      (implicit ctxt: ExecutionContext): Future[Response] = {
    for {
        future1 <- callFuture1(name) recoverWith {
         case e:Exception => return Future{Response(Nil,Nil,e.getMessage)}
        }
        future2 <- callFuture2(future1.data)
        future3 <- callFuture3(future1.data, future2.data)
    }  yield future3
  }

我收到运行时错误

ERROR] [08/31/2015 02:09:45.011] [play-akka.actor.default-dispatcher-3] [ActorSystem(play)] Uncaught error from thread [play-akka.actor.default-dispatcher-3] (scala.runtime.NonLocalReturnControl)
[error] a.a.ActorSystemImpl - Uncaught error from thread [play-akka.actor.default-dispatcher-3]
scala.runtime.NonLocalReturnControl: null

共有2个答案

谷梁星雨
2023-03-14

假设 future1future2future3 会分别引发名为 Future1ExceptionFuture2ExceptionFuture3Exception 的 Throwable 异常。然后,您可以从 getResponse() 方法返回相应的错误响应,如下所示:

def getResponse(name: String)
             (implicit ctxt: ExecutionContext): Future[Response] = {
  (for {
    future1 <- callFuture1(name)
    future2 <- callFuture2(future1.data)
    future3 <- callFuture3(future1.data, future2.data)
  } yield future3).recover {
    case e: Future1Exception =>
      // build appropriate Response(...)

    case e: Future2Exception =>
      // build appropriate Response(...)

    case e: Future3Exception =>
      // build appropriate Response(...)
  }
}

根据文档未来.恢复

创建一个新的future,它将处理这个future可能包含的任何匹配throwable。

钱华晖
2023-03-14

如果< code>Future失败,您可以使用< code>Future.recoverWith函数来自定义异常。

val failed = Future.failed(new Exception("boom"))
failed recoverWith {
  case e: Exception => Future.failed(new Exception("A prettier error message", e)
}

这将导致理解稍微丑陋:

for {
  future1 <- callFuture1(name) recoverWith {
               case npe: NullPointerException =>
                 Future.failed(new Exception("how did this happen in Scala ?", npe))
               case e: IllegalArgumentException =>
                 Future.failed(new Exception("better watch what you give me", e))
               case t: Throwable =>
                 Future.failed(new Exception("pretty message A", t))
             }
  future2 <- callFuture2(future1.data) recoverWith {
               case e: Exception => Future.failed(new Exception("pretty message B", e))
             }
  future3 <- callFuture3(future1.data, future2.data) recoverWith {
               case e: Exception => Future.failed(new Exception("pretty message C", e))
             }
} yield future3

请注意,如果您想添加除错误消息之外的更多信息,也可以定义自己的异常来代替< code>Exception。

如果您不希望细粒度控制根据失败的未来中的Throwable(如callFuture1)设置不同的错误消息,您可以使用隐式类来丰富将来,以设置更简单的自定义错误消息:

implicit class ErrorMessageFuture[A](val future: Future[A]) extends AnyVal {
  def errorMsg(error: String): Future[A] = future.recoverWith {
    case t: Throwable => Future.failed(new Exception(error, t))
  }
}

你可以这样使用:

for {
  future1 <- callFuture1(name) errorMsg "pretty A"
  future2 <- callFuture2(future1.data) errorMsg "pretty B"
  future3 <- callFuture3(future1.data, future2.data) errorMsg "pretty C"
} yield future3

在这两种情况下,直接使用 errorMsgrecoverWith,您仍然依赖于 Future,因此,如果 Future 失败,则不会执行以下 Futures,您可以直接使用失败的 Future 中的错误消息。

您没有指定要如何处理错误消息。例如,如果要使用错误消息创建其他响应,则可以使用 recoverWithrecover

future3 recover { case e: Exception =>
  val errorMsg = e.getMessage
  InternalServerError(errorMsg)
}
 类似资料:
  • 如果 Scala 未来失败,并且没有延续“观察到”该故障(或者唯一的延续使用 map/flatMap 并且在发生故障时不运行),那么错误就不会被发现。我希望至少记录这些错误,以便我可以找到错误。 我使用术语“观察到的错误”,因为在.Net Tasks中,当GC收集Task对象时,有机会捕获“未观察到的任务异常”。同样,使用同步方法,可以记录终止线程的未捕获异常。 在Scala futures中,“

  • 我正在阅读Scala Cookbook(http://shop.oreilly.com/product/0636920026914.do) 有一个与未来使用相关的例子,涉及理解。 到目前为止,我对理解的理解是,当与一个集合一起使用时,它会产生另一个相同类型的集合。例如,如果每个< code>futureX的类型为< code>Future[Int],则以下内容也应为< code>Future[In

  • 问题内容: 当我的discord bot上网时间过长(大约3-4小时)时,会随机出现此错误,但有时该错误发生得更早,有时又更晚。真的很困扰我 问题答案: 我在自己的代码中为这个问题努力了一段时间。主要问题是跟踪是完全无用的, 并且 错误很少发生,以至于使“在终端中运行并等待”是徒劳的任务。最终,我能够弄清楚Discord.js客户端本身正在引发错误- 在我阅读的任何文档中都没有提到此错误,因此我没

  • 我试图创建一个简洁的结构,用于理解基于未来的业务逻辑。下面是一个示例,其中包含一个基于异常处理的工作示例: 然而,这可能被视为一种非功能性或非Scala的处理方式。有更好的方法吗? 请注意,这些错误来自不同的来源——有些在业务级别(“检查所有权”),有些在控制器级别(“授权”),有些在数据库级别(“找不到实体”)。因此,从单一常见错误类型派生它们的方法可能不起作用。

  • 问题内容: 我之前从未遇到过此错误,所以我不确定该怎么做或意味着什么 未处理的异常类型 它在以下代码中发生: 它给了我2个选项“添加抛出声明”和“使用try / catch进行环绕”。 我该怎么办,为什么? 问题答案: 这意味着您要调用的方法已使用指令声明了从类派生的异常。当以这种方式声明一个方法时,您将被迫使用一个块来处理该异常,或者将一个相同的(对于相同的异常或超类型)语句添加到您的方法声明中

  • 错误: 我的前端vue应用程序正在和后端正在我正在请求axios从vue文件到后端的get请求。 这就是我的终点 这个错误的原因是什么?