Scala Futures 中如何处理异常?
我实现了一个简单的作业处理器,用于处理 futures 中的子作业(scala.actors.Futures)。这些 future 本身可以为处理子作业创建更多的 future。现在,如果这些子作业之一引发异常,我希望作业处理器回复该作业的错误消息。我有一个用于发现失败子作业的解决方案,但我不确定这是否是最佳解决方案。基本上它的工作原理是这样的:
sealed trait JobResult
case class SuccessResult(content: String) extends JobResult
case class FailedResult(message: String) extends JobResult
for(subjob <- subjobs) yield {
future {
try {
SuccessResult(process(subjob))
} catch {
case e:Exception => FailedResult(e.getMessage)
}
}
}
顶层的结果是 JobResults 的列表的列表的递归列表...。我递归地在列表中搜索失败的结果,然后根据结果的类型返回错误或组合结果。 这可行,但我想知道是否有更优雅/更简单的解决方案来处理期货中的异常?
I implemented a simple job processor that processes subjobs within futures (scala.actors.Futures). These futures themselves can create more futures for processing subjobs. Now, if one of these subjobs throws an exception, i want the job processor to reply with an error message for that job. I have a workaround solution for discovering failed subjobs, but i'm not sure if that's the best solution. Basically it works like this:
sealed trait JobResult
case class SuccessResult(content: String) extends JobResult
case class FailedResult(message: String) extends JobResult
for(subjob <- subjobs) yield {
future {
try {
SuccessResult(process(subjob))
} catch {
case e:Exception => FailedResult(e.getMessage)
}
}
}
The result at the top level is a recursive List of Lists of Lists... of JobResults. I recursively search the List for a failed Result and then return an error or the combined result depending on the types of results.
That works but i'm wondering if there's is a more elegant/easier solution for dealing with exceptions in futures?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您现在所做的方式本质上就是 scala.Either 的设计目的。请参阅 http://www.scala-lang.org/api/current/ scala/Either.html
The way you do it now, is essentially what scala.Either was designed for. See http://www.scala-lang.org/api/current/scala/Either.html
现代 scala future 与
Either
类似,因为它们要么包含成功的结果,要么包含Throwable
。如果你在 scala 2.10 中重新访问这段代码,我想你会发现这种情况非常愉快。具体来说, scala.concurrent.Future [T] 从技术上讲只有“is-a”
Awaitable[T]
,但是_.onComplete
和Await.ready(_, timeout)。 value.get
都将其结果显示为 scala.util.Try[T],它很像Either[Throwable, T]
因为它要么是结果,要么是异常。奇怪的是,
_.transform
需要两个映射函数,一个用于T =>; U
和一个Throwable =>; Throwable
并且(除非我遗漏了一些东西)没有变压器将未来映射为Try[T] =>尝试[U]
。Future
的.map
将允许您通过简单地在映射函数中抛出异常来将成功转变为失败,但它仅将其用于原始的成功。代码>未来。它的
.recover
,同样可以转败为胜。如果您希望能够将成功更改为失败,反之亦然,您需要自己构建一些由_.map
和_.recover
组合而成的东西或者使用_.onComplete
链接到新的 scala.concurrent.Promise[U] 像这样:它会像这样使用:
这会给出类似这样的东西:(
或者你可以“pimp”
Future
到具有隐式 def 的RichFutureWithFlexibleTransform
中,并使flexibleTransform
成为其中的成员函数,删除fut
参数并简单地使用 < code>this)(更好的是采用
Try[T] => Future[U]
并将其命名为flexibleFlatMap
这样你就可以做异步的事情在变换中)Modern scala futures are like
Either
in that they contain either a successful result or aThrowable
. If you re-visit this code in scala 2.10, i think you'll find the situation quite pleasant.Specifically, scala.concurrent.Future[T] technically only "is-a"
Awaitable[T]
, but_.onComplete
andAwait.ready(_, timeout).value.get
both present its result as a scala.util.Try[T], which is a lot likeEither[Throwable, T]
in that it's either the result or an exception.Oddly,
_.transform
takes two mapping functions, one forT => U
and one forThrowable => Throwable
and (unless i'm missing something) there's no transformer that maps the future asTry[T] => Try[U]
.Future
's.map
will allow you to turn a success into a failure by simply throwing an exception in the mapping function, but it only uses that for successes of the originalFuture
. Its.recover
, similarly can turn a failure into a success. If you wanted to be able to change successes to failures and vice-versa, you'd need to build something yourself that was a combination of_.map
and_.recover
or else use_.onComplete
to chain to a new scala.concurrent.Promise[U] like so:which would be used like so:
which would give something like this:
(or you could "pimp"
Future
into aRichFutureWithFlexibleTransform
with an implicit def and makeflexibleTransform
a member function of that, dropping thefut
param and simply usingthis
)(even better would be to take
Try[T] => Future[U]
and call itflexibleFlatMap
so you could do async things in the transform)