Scala下两个有执行顺序要求的Future调用的错误处理与回滚实现
纯Scala 2.13原生Future实现带回滚的顺序调用方案
不需要引入第三方库,直接基于原生Future的flatMap链式调用结合Either的分支匹配即可实现需求。原生for推导式没有内置错误分支的回滚处理钩子,硬写反而会增加冗余逻辑,更推荐直接手写flatMap分支处理。
已有方法签名参考:
// 业务处理方法 def processUser(..): Future[Either[Error, UserStatus]] def processTransactions(..): Future[Either[Error, TransactionStatus]] // 回滚方法(可根据实际签名调整) def unprocessUser(status: UserStatus): Future[Unit]
完整实现代码
import scala.concurrent.Future // 注意替换为业务实际使用的ExecutionContext,不建议直接用全局默认 import scala.concurrent.ExecutionContext.Implicits.global def runProcessFlow(user: User, ...): Future[Either[Error, Unit]] = { processUser(user).flatMap { // 规则1:processUser返回错误,直接透传错误,不调用后续transaction方法 case Left(userError) => Future.successful(Left(userError)) // processUser执行成功,执行transaction逻辑 case Right(userStatus) => processTransactions(...).flatMap { // 规则2:两个方法都执行成功,返回成功 case Right(_) => Future.successful(Right(())) // 规则3:transaction执行失败,先回滚processUser的操作再返回错误 case Left(txnError) => unprocessUser(userStatus).map(_ => Left(txnError)) } } }
简化写法(使用Either.fold)
如果偏好更简洁的函数式写法,可以用Either自带的fold方法替代模式匹配,逻辑完全等价:
def runProcessFlow(user: User, ...): Future[Either[Error, Unit]] = { processUser(user).flatMap( _.fold( userErr => Future.successful(Left(userErr)), userStatus => processTransactions(...).flatMap( _.fold( txnErr => unprocessUser(userStatus).map(_ => Left(txnErr)), _ => Future.successful(Right(())) ) ) ) ) }
注意事项
- 如果需要忽略回滚方法
unprocessUser自身的执行错误,避免回滚失败覆盖原始业务错误,可以给回滚方法增加异常捕获逻辑:unprocessUser(userStatus).recover{ case _ => () }.map(_ => Left(txnError)) - 如果你需要处理
Future层面抛出的非受检异常(比如方法内部直接抛异常而非返回Left),可以在对应Future后追加recover/recoverWith逻辑做兼容处理。
内容的提问来源于stack exchange,提问作者Blankman
相关产品推荐
相关产品推荐

