假设我有一个应用程序,可以从服务器下载文件并将其上传到另一台服务器。
下载文件不一定在服务器上。
因此,当文件不存在时,我想跳过它,而不是继续上传它,并确保仅下载/上传现有文件。 (即,任何单个下载异常都不应停止所有其他下载和上传过程)
未来应该成功,没有结果(单位),或者失败,并带有失败的路径。
处理这种情况的标准方法是什么?
def downloadFile(path: String): Future[DownloadFile]
def uploadFile(file: DownloadFile): Future[Unit]
Future.sequence(
paths.map { path =>
for {
downloadedFile <- downloadFile(path)
_ <- uploadFile(downloadedFile)
} yield Unit
}
)
答案 0 :(得分:4)
考虑
val listOfFutures = List(
Future(1),
Future(throw new RuntimeException("path/foo")),
Future(2),
Future(throw new RuntimeException("path/bar")),
)
Future.traverse(listOfFutures)(_.transform {
case Success(v) => Try(Some(v))
case Failure(e) => Try(None)
}).map(_.flatten) andThen { case v => println(v) }
输出
Success(List(1, 2))
注意Future.sequence
是Future.traverse
的简单版本。
应用注释,考虑像这样反转拼合
Future.traverse(listOfFutures)(_.transform {
case Success(v) => Try(None)
case Failure(e) => Try(Some(e.getMessage))
}).map { results =>
if (results.flatten.nonEmpty) throw new RuntimeException(s"Bad paths: ${results.flatten.mkString(",")}")
else ()
} andThen { case v => println(v) }
输出
Failure(java.lang.RuntimeException: Bad paths: path/foo,path/bar)
答案 1 :(得分:1)
您可以使用Either
Future.sequence(
Seq("path1", "path2").map { path =>
(for {
downloadedFile <- downloadFile(path)
_ <- uploadFile(downloadedFile)
} yield Right(Unit))
.recover { case ex: Exception => Left(ex) }
}
)
这将返回List(Right(object scala.Unit), Left(java.lang.Exception: Bad path))
或与Option
相同:
Future.sequence(
Seq("path1", "path2").map { path =>
(for {
downloadedFile <- downloadFile(path)
_ <- uploadFile(downloadedFile)
} yield None)
.recover { case ex: Exception => Some(ex) }
}
)
返回List(None, Some(java.lang.Exception: Bad path))
然后可以过滤列表。