2012-07-17 18 views
13

W aplikacji Play Framework 2.0.1 (Scala) używamy biblioteki klienta usług WWW, która zwraca java.util.concurrent.Future jako odpowiedzi.Jak zawinąć java.util.concurrent.Future w Akka Future?

Zamiast blokowania aplikacji grać na wezwanie get(), chcielibyśmy, aby owinąć j.u.c.Future w akka.dispatch.Future, tak, że z łatwością możemy korzystać ze struktury Play AsyncResult przetwarzanie.

Czy ktoś to zrobił wcześniej, czy ma bibliotekę lub przykładowy kod?


UPDATE: Najbliższy rzeczą odkryliśmy, jest to dyskusja Google Groups: https://groups.google.com/forum/#!topic/play-framework/c4DOOtGF50c

... jeśli wszystko masz to zwykły jucFuture najlepiej można zrobić, aby stworzyć nie blokującym rozwiązaniem jest przyjęcie jucFuture i obietnicy oraz przekazanie ich wątkowi prowadzącemu pętlę odpytywania, która uzupełni obietnicę z wynikiem przyszłości po jej zakończeniu.

Czy ktoś ma przykładową realizację tego?

Odpowiedz

7

@Viktor Klang: Rozumiemy, że j.u.c.Future jest obrzydliwością. Ale właśnie to otrzymujemy z oprogramowania, które musimy zaakceptować, jak na razie.

Jak dotąd, to co mamy hacked razem:

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 
} 

Innymi słowy, należy utworzyć oddzielną Akka Promise (write-boczny Future) odpowiadający j.u.c.Future, rozpoczyna wywołanie zwrotne pollJavaFutureUntilDoneOrCancelled, aby zaktualizować Obietnicę przez sondowanie "obrzydliwości" i zwraca Obietnicę do osoby dzwoniącej.

Jak więc "odpytać", aby zaktualizować obietnicę Akka na podstawie stanu 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) 
     } 
    } 
    } 
} 

To jest próba tego, o czym była mowa w dyskusji grup dyskusyjnych, do której się odwoływałem w pytaniu. Używa programu planującego Akka do wywoływania siebie co 50 ms w celu sprawdzenia, czy j.u.c.Future zostało wykonane lub anulowane. Ilekroć tak się stanie, aktualizuje się obietnicę Akka z zakończonym stanem.

@Victor Klang, et al:

Jest to najlepsza praktyka? Czy znasz lepszy sposób na zrobienie tego? Czy brakuje nam tu minusów, o których powinniśmy wiedzieć?

Dzięki za pomoc.

+0

Oczywistym minusem jest to, że w najgorszym wypadku może to spowodować duże opóźnienie odpowiedzi. Jeśli na przykład ustawienia domyślne i Twoja przyszłość zakończy się po 1 ms po sprawdzeniu, może to spowodować opóźnienie około 100ms. Można to jednak zmienić, ustawiając 'scheduler.Ustawienie "czasu trwania" w konfiguracji. – drexin

+0

@drexin prawda, ale czas trwania tyknięcia i kompromis w zakresie częstotliwości sond będą obecne w każdym rozwiązaniu opartym na głosowaniu, prawda? –

+1

Oczywiście, ale kiedy prosiłeś o wady, chciałem ci tylko powiedzieć, że zależy to nie tylko od opóźnienia paramu wywołania 'scheduleOnce', ale także od ustawienia w konfiguracji akka. Jeśli możesz żyć z opóźnieniem, powinno to być użyteczne rozwiązanie. – drexin

0

Należy użyć akka.dispatch.Futures.future() z 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

+0

To zasadniczo powoduje więcej wątków niż to konieczne, jeden z nich blokuje i nie jest wcale lepszy niż po prostu wywołanie javaFuture.get w głównym wątku. Wprowadzenie akka przyszłości nie jest tu korzystne, z wyjątkiem sytuacji ekstremalnych, gdzie niezbędna jest kompatybilność komponentów. – vishr

Powiązane problemy