2015-06-20 17 views
5

wersja skrócona:Java/Scala Future napędzany przez zwrotnego

Jak mogę utworzyć Promise<Result> który jest zakończony na spuście wywołania zwrotnego?

Długa wersja:

pracuję nad aplikacji, która zajmuje się usługami SOAP trzecich. Żądanie od użytkownika deleguje jednocześnie do wielu usług SOAP, agreguje wyniki i odsyła z powrotem do użytkownika.

System musi być skalowalny i powinien umożliwiać wielu równoczesnych użytkowników. Ponieważ każde żądanie użytkownika kończy się wywoływaniem około 10 wywołań usługi WWW i blokowaniem każdego połączenia przez około 1 sekundę, system musi być zaprojektowany z nieblokującymi operacjami wejścia/wyjścia.

Używam Apache CXF w Play Framework (Java) dla tego systemu. Udało mi się wygenerować proxy Asynchronous WS Client i włączyć transport asynchroniczny. Nie jestem w stanie dojść do tego, w jaki sposób zwrócić wątek Future to Play, gdy deleguję do wielu serwerów proxy usług sieci Web, a wyniki zostaną uzyskane jako callbacki.

Opcja 1: Używanie wywołania metody async zwrócenie Javy Przyszłość.

Zgodnie z opisem w tym artykule: scala.concurrent.Future wrapper for java.util.concurrent.Future, nie ma możliwości przekonwertowania przyszłości Java na Scala Future. Jedynym sposobem uzyskania wyniku z przyszłości jest wykonanie Future.get(), która blokuje dzwoniącego. Ponieważ wygenerowane przez CXF proxy zastępują Java Future, ta opcja jest wykluczona.

Opcja 2: Użyj Scala Future.

Ponieważ CXF generuje interfejsy proxy, nie jestem pewien, czy mogę w jakiś sposób interweniować i zwrócić Scala Future (AFAIK Akka używa Scala Futures) zamiast Javy Future?

Opcja 3: Użyj metody oddzwaniania.

Metody asynchroniczne generowane przez CXF, które zwracają Java Future, również pobierają obiekt wywołania zwrotnego, który, jak przypuszczam, zapewni wywołanie zwrotne, gdy wynik będzie gotowy. Aby użyć tego podejścia, będę musiał zwrócić Future, która będzie czekać, aż otrzymam wywołanie zwrotne.

Myślę, że Opcja 3 jest najbardziej obiecująca, chociaż nie mam pomysłów na to, w jaki sposób mogę zwrócić Obietnicę, która zostanie zakończona po otrzymaniu oddzwonienia. Mogę mieć wątek czekający w while(true) i czekanie pomiędzy, aż do uzyskania wyniku. Ponownie, nie wiem, jak mogę przejść do wait bez blokowania wątku?

W skrócie, próbuję zbudować system, który wykonuje wiele wywołań usług sieciowych SOAP, gdzie każde wywołanie blokuje się przez dłuższy czas. System może z łatwością wyczerpać wątki w przypadku wielu równoczesnych wywołań usług internetowych. Pracuję nad znalezieniem rozwiązania, które nie jest oparte na blokowaniu I/O, co pozwala na jednoczesną obsługę wielu bieżących wywołań usług sieciowych.

+0

Zaskoczony na 4 głosy, aby zamknąć pytanie, nawet gdy mam krótszą wersję pytania, które jest bardzo precyzyjne. –

Odpowiedz

1

Opcja 3 wygląda dobrze :) Kilka importów na początek ...

, a tylko do zilustrowania punkt, oto szydził CXF API, które wykonuje wywołania zwrotnego:

def fetch(url: String, callback: String => Unit) = { 
    callback(s"results for $url") 
} 

Tworzenie obietnicę, zadzwoń API z obietnicą jako callback:

val promise = Promise[String] 
fetch("http://corp/api", result => promise.success(result)) 

Następnie możesz wziąć promise.future, która jest instancją Future w Twojej aplikacji Play.

By to sprawdzić, można to zrobić:

Await.result(promise.future, Duration.Inf) 

które będą blokować oczekiwaniu na rezultat, w tym momencie powinieneś zobaczyć „wyniki dla http://corp/api” w konsoli.

+2

Dzięki za przykładowy kod, mimo że korzystam z gry Java. Myślę, że brakowało mi punktu, że "Obietnica" jest właśnie tym, co można osiągnąć. W przypadku Play Java jest to "play.libs.F.RedeemablePromise". Mogę więc zwrócić instancję 'RedeemablePromise' i przekazać uchwyt' javax.xml.ws.AsyncHandler', który ma wbudowany obiekt obietnicy, dzięki czemu obiekt wywołania zwrotnego może przekazać obietnicę za pośrednictwem wywołania 'success()'. Myślę, że rozumiem różnicę między przyszłością a obietnicą, którą uważam za bardzo podobną. –

+1

Udało mi się uzyskać asynchroniczne działanie za pomocą 'Promise'. Dzięki @bjfletcher –

Powiązane problemy