【问题标题】:Best practice to make cleanup after Scala Future is completeScala Future 完成后进行清理的最佳实践
【发布时间】:2020-04-16 00:43:06
【问题描述】:

我想在Future 完成后进行一些清理(例如关闭数据库连接)。
目前我是这样实现的:

Future { ... } onComplete {
  case Success(v) =>
    // ...
    conn.close()
  case Failure(ex) =>
    // ...
    conn.close()
}

有重复的代码,也很乏味。
有什么最佳实践吗?

【问题讨论】:

    标签: scala future resource-cleanup


    【解决方案1】:

    我喜欢用map,你可以这样做:

    val mapped: Future[String] = future.map(_ => "OK").recover{case _ => "KO"}
    

    【讨论】:

    • 本可以使用两次调用并不是好的做法。使用单个调用,例如 onCompleteandThentransform
    【解决方案2】:

    由于对成功和失败都执行相同的操作conn.close(),因此请考虑像这样使用andThen 作为副作用来执行它

    Future { ... } andThen { _ => conn.close() }
    

    同样,我们可以使用onComplete

    Future { ... } onComplete { _ => conn.close() }
    

    andThenonComplete的区别在于后者会返回Unit,即丢弃Future的返回值。

    【讨论】:

      【解决方案3】:

      可悲的事实是,Scala Futures 没有内置这个基本功能。因此,我强烈建议使用现代效果系统,如 ZIO 或猫效果,它们都解决了这个问题以及 Futures 的无数其他问题有。做你想做的最简单的方法是使用bracket 方法:

      https://zio.dev/docs/overview/overview_handling_resources

      现在bracket 效果很好,但有一种方法通常效果更好:Managed 类型。如果您在获取资源时始终使用Managed,则几乎不可能编写泄漏资源的代码:

      https://zio.dev/docs/datatypes/datatypes_managed

      也就是说,如果你绝对必须使用 Futures,你必须编写自己的 try-finally 等价物。或者你可以使用我的:

        def tryFinally[A](tryy: => Future[A])(finallyy: => Future[Any])(
        implicit ec: ExecutionContext): Future[A] =
          Future.fromTry(Try(tryy)).flatten.transformWith { t =>
            finallyy.flatMap((_: Any) => Future.fromTry(t))
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-01
        • 1970-01-01
        • 2013-01-23
        • 2022-01-23
        相关资源
        最近更新 更多