未来[A]与未来[Throwable \ / A]

时间:2014-12-02 23:22:48

标签: scala error-handling future

为什么有些人在scala.concurrent.Future使用scala Either或scalaz' \/而不是使用未来的失败状态来代表失败?

你如何处理错误呢?你如何在快乐的道路上连接电话?


通过一些例子更新:

converting Akka's Future[A] to Future[Either[Exception,A]]

Scalaz Task - the missing documentation 这个回答了为什么部分,并建议使用scalaz.EitherT来锁定来电(\/的那个,EitherTry怎么样?),但我想知道如果一个人应该使用Future.failed,在什么条件等,以及如何检查失败。

我不确定这是否是一种普遍的做法,这就是我要问的原因。 :)

2 个答案:

答案 0 :(得分:4)

我个人使用Either在未来,当我有"失败,我可以期待"并且可以做些什么来从中恢复。特别是如果我需要向API的外部用户显示可能的故障信息

sealed trait UserServiceError
case object UserDbNotAvailable extends UserServiceError
case object UserNotFoung extends UserServiceError

def getUser(id: Long): Future[UserServiceError \/ User]

此代码更明确地说明可能发生的故障。在某些情况下,它可能很重要。

使用Future [User]和Future.recover可以实现同样的效果,但在这种情况下,有关可能的故障的信息不在类型中(可以在文档中)

但我同意这是一个非常有争议的设计决定,因为Try已经设计用于故障处理。

答案 1 :(得分:3)

我以与处理异常相同的方式处理Future的失败状态:它们用于表示编程错误或系统故障(例如OutOfMemoryError)的意外故障。因此,除非是在一个非常高级别的“重试整个任务”的方式,否则它们不会被捕获或处理。

失败的期货不是非常类型安全的(失败只是Throwable),并且可以将这些系统级故障与可以以可预测的方式处理的更多语义故障混为一谈。因此,如果我在我的系统内“失败”,例如Unauthorized,然后我宁愿将其表示为Either,类似于Future[Unauthorized \/ MessageData]。然后有三种可能的状态:

  • Success(\/-(data)) - 成功
  • Success(-\/(unauthorized)) - “预期”失败。我知道如何处理的东西,例如通过向用户显示特定消息或返回特定返回代码。不应该为程序员设置警报。
  • Failure(throwable) - 意外的系统级故障。只能使用通用错误页面或某些错误页面来处理。应该启动监控并提醒程序员。

我曾经使用monad变换器来更轻松地编写快乐路径(即EitherT[Future, Unauthorized, MessageData]),这非常有效,但现在我正在研究一种更通用的方法(我的scalaz-transfigure库)。