Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I wrap a java.util.concurrent.Future in an Akka Future?

In a Play Framework 2.0.1 (Scala) application, we are using a web service client library which returns java.util.concurrent.Future as responses.

Instead of blocking the Play app on the get() call, we'd like to wrap the j.u.c.Future in an akka.dispatch.Future, so that we can easily use the play framework's AsyncResult processing.

Has anyone done this before, or have a library or example code?


UPDATE: The closest thing we've found is this google groups discussion: https://groups.google.com/forum/#!topic/play-framework/c4DOOtGF50c

...if all you have is a plain j.u.c.Future the best you can do to create a non blocking solution is to take the j.u.c.Future and a Promise, and give them to some thread running a polling loop that will complete the Promise with the result of the Future when it is done.

Does anyone have an example implementation of this?

like image 822
ms-tg Avatar asked Jul 17 '12 19:07

ms-tg


1 Answers

@Viktor Klang: We understand that j.u.c.Future is an abomination. But that's what we're getting back from a piece of software we must accept as given for the time being.

So far, this is what we've hacked together:

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
}

In other words, create a separate Akka Promise (the write-side of a Future) corresponding to the j.u.c.Future, kicks off the callback pollJavaFutureUntilDoneOrCancelled to update the Promise by polling the "abomination", and returns the Promise to the caller.

So how do we "poll" to update the Akka Promise based on the state of the j.u.c.Future?

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)
      }
    }
  }
}

This is an attempt at what was hinted at in the google groups discussion that I referenced in the question. It uses the Akka scheduler to call itself back every 50 ms to check if the j.u.c.Future is either done or cancelled. Whenever that happens, it updates the Akka Promise with the completed state.

@Victor Klang, et al:

Is this best practice? Do you know of a better way to do this? Are we missing a downside here that we should know about?

Thanks for any more help.

like image 79
ms-tg Avatar answered Nov 06 '22 06:11

ms-tg