我有一个返回未来的repo方法:
def insert(newUser: User): Future[User]
此方法可能因各种原因而失败,但是,我希望能够抓住其中一个原因并重新抛出其他原因。 如果我只是用Try
打包电话Try(userRepository.insert(usr)) match {
case Success(newUserFuture) => newUserFuture
case Failure(e) if e.getCause.getMessage.contains("duplicate key") => {
logger.warn(e.getMessage)
throw DuplicateEntityException("duplicate user record")
}
case Failure(e) => {
logger.error(e.getMessage)
throw e
}
}
结果,我得到Try[Future[User]]
,在这种情况下,由于未来成功创建,故障都不会发生。
在这一点上,我不知道如何处理它。理想情况下,我想从中获取Future[Either[String, User]]
(或类似的东西)。
我应该如何处理这种情况,或者我是否处于完全错误的方向?
按照建议编辑 可能的解决方案 我尝试过这样的事情:
userRepository.insert(usr).map(newUser => Right(newUser)) recoverWith {
case e: PSQLException if e.getMessage.contains("duplicate key") =>
Future.successful(Left("duplicate user record"))
}
答案 0 :(得分:4)
Future
将为您处理例外情况。您无需使用Try
包装未来的代码。
Future
也可以完成Try
的工作。
这行代码不是必需的
Try(userRepository.insert(usr))
我希望你的插入方法是这样的
def insert(newUser: User): Future[User] = Future { doSomeDBCall() }
在上面的方法中。如果doSomeDBCall()
失败。该例外将被未来安全捕获,并将作为Failure(exception)
传递给调用者。所以你不需要用Future
Try
捕获特定异常并抛出其他异常(传播其他异常)。
您可以使用recoverWith
处理异常并传播您不感兴趣的异常。
在下面的代码中处理SQLException
,并将其他异常传播给调用者。
userRepository.insert(usr).recoverWith {
case ex: SQLException => Future.successful(defaultValue)
case ex => Future.failed(ex)
}
答案 1 :(得分:1)
我认为你可以改变你的做法,并在案件中使用一个警卫清理一下代码。首先要让userRepository.insert(usr)
返回Future[Try[User]]
,这样您就可以只绘制未来,例如
def insert(user: User): Future[Try[User]]
然后可以像这样使用:
userRepository.insert(user).map {
case Success(insertedUser) => Right(insertedUser)
case Failure(ex) if ex.getCause.getMessage.contains("duplicate key") => throw DuplicateEntityException("duplicate user record")
case Failure(ex) => throw ex
}
结果将是Future[User]
,您可以附加回调(请参阅http://docs.scala-lang.org/overviews/core/futures.html)以对用户执行其他操作或处理异常。
答案 2 :(得分:0)
尝试类似的事情:
def futureToFutureTry[T](f: Future[T]): Future[Try[T]] =
f.map(Success(_)).recover {
case e: Throwable => {
Failure(e)
}
}
...
userRepository.insert(usr) map futureToFutureTry
用于检查
def checkOperations[A](operations: List[Try[A]]): Future[List[A]] = {
Future {
if (!operations.filter(_.isFailure).isEmpty) {
// there were some error
} else {
// all operations are ok
}
}