在 Scala Future 完成后进行清理的最佳实践



我想在Future完成后进行一些清理(例如关闭数据库连接(。
目前我以这种方式实现它:

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

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

由于在成功和失败时都执行相同的操作conn.close(),请考虑使用这样的andThen将其作为副作用执行

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

同样,使用我们可以做的onComplete

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

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

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

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

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

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

也就是说,如果你绝对必须使用期货,你必须编写你自己的 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))
}

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

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

最新更新