2015-06-20 9 views
5

Short Version angetrieben:Java/Scala Future durch einen Rückruf

Wie kann ich ein Promise<Result> erstellen, die auf einem Auslöser einer Rückruf abgeschlossen ist?

Lange Version:

ich auf eine Anwendung arbeite, die von Drittanbietern SOAP-Dienste befasst sich mit. Eine Anforderung von Benutzerdelegaten an mehrere SOAP-Dienste gleichzeitig aggregiert die Ergebnisse und sendet sie an den Benutzer zurück.

Das System muss skalierbar sein und mehrere gleichzeitige Benutzer zulassen. Wenn jeder Benutzer anfordert, ungefähr 10 Web-Service-Anrufe auszulösen und jeder Anruf für ungefähr 1 Sekunde blockiert, muss das System mit nicht-blockierenden E/A entworfen werden.

Ich verwende Apache CXF in Play Framework (Java) für dieses System. Ich habe es geschafft, die asynchronen WS-Client-Proxies zu generieren und den asynchronen Transport zu aktivieren. Was ich nicht herausfinden kann ist, wie man einen Future to Play Thread zurückgibt, wenn ich an mehrere Web Service Proxies delegiert habe und die Ergebnisse als Callbacks erhalten werden.

Option 1: Verwenden von asynchronen Methodenaufrufen, die Java Future zurückgeben.

Wie in diesem scala.concurrent.Future wrapper for java.util.concurrent.Future Thread beschrieben, gibt es keine Möglichkeit, wir können eine Java-Future in eine Scala-Zukunft konvertieren. Die einzige Möglichkeit, ein Ergebnis aus der Zukunft zu erhalten, ist Future.get(), was den Anrufer blockiert. Da die von CXF generierten Proxys Java Future zurückgeben, ist diese Option ausgeschlossen.

Option 2: Scala Future verwenden.

Da CXF die Proxy-Schnittstellen generiert, bin ich mir nicht sicher, ob es irgendeinen Weg gibt, wie ich ein Scala-Future (AFAIK Akka nutzt Scala-Futures) statt Java Future zurückgeben kann?

Option 3: Verwenden Sie den Rückruf-Ansatz.

Die von CXF generierten asynchronen Methoden, die Java Future zurückgeben, nehmen auch ein Callback-Objekt, das einen Callback liefert, wenn das Ergebnis fertig ist. Um diesen Ansatz zu verwenden, muss ich eine Zukunft zurückgeben, die warten wird, bis ich einen Rückruf erhalte.

Ich denke, Option 3 ist am vielversprechendsten, obwohl ich keine Ideen habe, wie ich eine Zusage zurückgeben kann, die bei Erhalt eines Rückrufs abgeschlossen wird. Ich könnte möglicherweise einen Thread warten in einem while(true) und dazwischen warten, bis das Ergebnis verfügbar ist. Nochmal, ich weiß nicht, wie ich in wait gehen kann, ohne den Thread zu blockieren?

Kurz gesagt, ich versuche, ein System zu bauen, das eine Menge von SOAP Web-Service-Anrufe macht, wo jeder Anruf für erhebliche Zeit blockiert. Das System kann bei vielen gleichzeitigen Web-Service-Aufrufen leicht von Threads ausgehen. Ich arbeite daran, eine Lösung zu finden, die blockierungsfrei E/A-basiert ist und viele laufende Web-Service-Anrufe gleichzeitig ermöglicht.

+0

Überrascht um 4 Stimmen, um die Frage zu schließen, auch wenn ich eine kürzere Version der Frage habe, die sehr genau ist. –

Antwort

1

Option 3 sieht gut aus :) Ein paar Importe zu beginnen mit ...

und nur um den Punkt zu veranschaulichen, hier ein verspottete CXF API, die den Rückruf nimmt:

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

ein Versprechen erstellen, API-Aufruf mit Versprechen wie Rückruf:

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

Dann können Sie promise.future, die eine Instanz von Future ist, in Ihre Play App übernehmen.

es zu testen, können Sie dies tun:

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

, die das Ergebnis erwarten blockiert, an dem Sie anweisen „Ergebnisse für http://corp/api“ in der Konsole zu sehen.

+2

Danke für den Beispielcode, obwohl ich Play Java verwende. Ich denke, der Punkt, den ich vermisste, war, dass "Promise" genau das ist, um dies zu erreichen. Bei Play Java ist dies 'play.libs.F.ReememablePromise'. So kann ich eine Instanz von 'RedeemablePromise' zurückgeben und das Handle von' javax.xml.ws.AsyncHandler' übergeben, in dem das Promise-Objekt eingebettet ist, so dass das Callback-Objekt durch 'success()' Aufruf in Versprechen geben kann. Ich denke, ich verstehe jetzt den Unterschied zwischen Zukunft und Versprechen, die ich denke, sind sehr ähnlich. –

+1

Ich habe es geschafft, mit 'Promise' async zu arbeiten. Danke @bjfletcher –