Подтвердить что ты не робот

Как обернуть java.util.concurrent.Future в будущее Akka?

В приложении Play Framework 2.0.1 (Scala) мы используем клиентскую библиотеку веб-сервиса, которая возвращает java.util.concurrent.Future в качестве ответов.

Вместо того, чтобы блокировать приложение Play при вызове get(), мы хотели бы обернуть j.u.c.Future в akka.dispatch.Future, чтобы мы могли легко использовать обработку фрейма воспроизведения AsyncResult.

Кто-нибудь делал это раньше или имел библиотечный или примерный код?


UPDATE. Самое близкое, что мы обнаружили, это обсуждение групп google: https://groups.google.com/forum/#!topic/play-framework/c4DOOtGF50c

... если все, что у вас есть, это простой jucFuture, лучшее, что вы можете сделать для создания неблокирующего решения, - это взять jucFuture и Promise и дать им какой-то поток, выполняющий цикл опроса, который завершит Обещайте с результатом Будущего, когда это будет сделано.

Есть ли у кого-нибудь пример реализации этого?

4b9b3361

Ответ 1

@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
}
Другими словами, создайте отдельный Akka Promise (сторона записи Future), соответствующая j.u.c.Future, отменит обратный вызов pollJavaFutureUntilDoneOrCancelled , чтобы обновить Promise, опросив "мерзость", и возвращает обещание вызывающему абоненту.

Итак, как мы можем "опросить", чтобы обновить обещание Akka на основе состояния 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)
      }
    }
  }
}

Это попытка того, что было намечено в обсуждении групп google, на которое я ссылался в вопросе. Он использует планировщик Akka для вызова себя каждые 50 мс, чтобы проверить, что j.u.c.Future либо выполнен, либо отменен. Всякий раз, когда это происходит, он обновляет обещание Akka с завершенным состоянием.

@Victor Klang и др.:

Это лучшая практика? Вы знаете лучший способ сделать это? Не хватает ли здесь недостатка, о котором мы должны знать?

Спасибо за дополнительную помощь.

Ответ 2

Вы должны использовать 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 для полного примера