如何在Akka Future中包装java.util.concurrent.Future?

时间:2012-07-17 19:04:34

标签: scala playframework-2.0 akka future

在Play Framework 2.0.1(Scala)应用程序中,我们使用的是一个Web服务客户端库,它返回java.util.concurrent.Future作为响应。

我们不想在get()调用中阻止Play应用,而是将j.u.c.Future封装在akka.dispatch.Future中,以便我们可以轻松使用播放框架{{1}处理。

之前是否有人这样做过,或者有图书馆或示例代码?


更新:我们发现最接近的是谷歌小组讨论:https://groups.google.com/forum/#!topic/play-framework/c4DOOtGF50c

  

...如果您拥有的只是一个简单的jucFuture,那么创建非阻塞解决方案的最佳方法是使用jucFuture和Promise,并将它们提供给运行轮询循环的某个线程来完成完成时承诺未来的结果。

有没有人有这样的示例实现?

2 个答案:

答案 0 :(得分:7)

@Viktor Klang:我们知道j.u.c.Future是令人厌恶的。但这就是我们从一个软件中得到的回报,我们必须暂时接受它。

到目前为止,这是我们共同攻击的内容:

def wrapJavaFutureInAkkaFuture[T](javaFuture: java.util.concurrent.Future[T], maybeTimeout: Option[Duration] = None)(implicit system: ActorSystem): akka.dispatch.Future[T] = {
  val promise = new akka.dispatch.DefaultPromise[T]
  pollJavaFutureUntilDoneOrCancelled(javaFuture, promise, maybeTimeout.map(_.fromNow))
  promise
}

换句话说,创建一个与Promise对应的单独的Akka Futurej.u.c.Future的写入侧),启动回调pollJavaFutureUntilDoneOrCancelled以更新通过轮询“憎恶”来承诺,并将Promise返回给调用者。

那么我们如何根据j.u.c.Future的状态“轮询”更新Akka Promise?

def pollJavaFutureUntilDoneOrCancelled[T](javaFuture: java.util.concurrent.Future[T], promise: akka.dispatch.Promise[T], maybeDeadline: Option[Deadline] = None)(implicit system: ActorSystem) {
  if (maybeDeadline.exists(_.isOverdue)) javaFuture.cancel(true);

  if (javaFuture.isDone || javaFuture.isCancelled) {
    promise.complete(allCatch either { javaFuture.get })
  } else {
    Play.maybeApplication.foreach { implicit app =>
      system.scheduler.scheduleOnce(50 milliseconds) {
        pollJavaFutureUntilDoneOrCancelled(javaFuture, promise, maybeDeadline)
      }
    }
  }
}

这是对我在问题中引用的Google群组讨论中暗示的内容的尝试。它使用Akka调度程序每50毫秒调用一次自己来检查j.u.c.Future是完成还是取消。每当发生这种情况时,它会以完成状态更新Akka Promise。

@Victor Klang,等人:

这是最佳做法吗?你知道更好的方法吗?我们在这里错过了一个我们应该知道的缺点吗?

感谢您提供更多帮助。

答案 1 :(得分:0)

您应该akka.dispatch.Futures.future()使用java.util.concurrent.Callable

val akkaFuture: akka.dispatch.Future[String] = akka.dispatch.Futures.future(
  new java.util.concurrent.Callable[String] {
    def call: String = {
      return "scala->" + javaFuture.get
    }
}, executionContext)

Gist for complete example