2014-12-02 66 views
2

为什么有些人使用scala的Either或scalaz的\/而不是使用Future的失败状态来代替scala.concurrent.Future中的失败?未来[A]与未来[Throwable /A]

那么您如何处理错误,以及如何将呼叫链接到快乐路径上?


更新一些例子:

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

Scalaz Task - the missing documentation 这一个回答了为什么部分,并使用scalaz.EitherT的链接调用(?这对\/,那EitherTry)暗示,但我不知道是否应该使用Future.failed,在什么条件下等,以及如何检查失败。

我不确定这是否是普遍的做法,这就是为什么我问。 :)

+0

这可能是一些稍微好一些的例子。 – 2014-12-02 23:30:16

回答

3

我对待Future的失败状态与我处理异常的方式相同:它们用于意外的故障,指示编程错误或系统故障,如OutOfMemoryError s。因此,除非是高水平的“重试整个任务”,否则预计不会被抓住或处理。

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

  • Success(\/-(data)) - 成功
  • Success(-\/(unauthorized)) - “预期” 的故障。我知道如何处理特定的事物,例如通过向用户显示特定的消息或返回特定的返回码。不应该为程序员引发警报。
  • Failure(throwable) - 意外的系统级故障。只能用通用的错误页面或其他方式处理。应该启动监视并提醒程序员。

我曾经使用monad变压器来使构成快乐路径更容易(即,EitherT[Future, Unauthorized, MessageData]),这工作得很好,但现在我正在寻找更通用的方法(我的scalaz-transfigure库)。

4

我个人使用或者在未来,当我有“我可以期待的失败”,并可以做些事情来恢复他们。特别是,如果我需要做出明确的以API

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

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

的外部用户可能的故障信息此代码是更为明确,什么都可能发生故障。在某些情况下,这可能很重要。

同样可以与未来[用户]和Future.recover但有关可能的故障这种情况下,信息可以实现不型(可以在文档)

不过,我同意,这是很有争议的设计决定,因为Try已经设计用于故障处理。

+0

但是,如果您尝试对结果进行处理,则无论如何,如果您收到User或UserServiceError,那么它与“成功(用户)”和“失败(userServiceError)”上的模式匹配确实不同。 ? – benji 2014-12-03 03:05:22

+0

我在'未来[UserServiceError,User]]中看到的优点是,你可以期待你会得到什么样的错误,如果你使用了一个你没有写过的API,但是还有其他优点,这很好吗? – benji 2014-12-03 03:06:51