使用Scala

时间:2016-10-18 07:44:40

标签: scala playframework error-handling future

我有一个返回未来的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"))
    }

3 个答案:

答案 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
     }
}