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?
@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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With