Java / Scala Future driven by a callback

只谈情不闲聊 提交于 2019-12-22 05:42:00

问题


Short Version:

How can I create a Promise<Result> which is completed on a trigger of a callback?

Long Version:

I am working on an application which deals with third-party SOAP services. A request from user delegates to multiple SOAP services simultaneously, aggregates the results and sends back to the user.

The system needs to be scalable and should allow multiple concurrent users. As each user requests ends up triggering about 10 web service calls and each call blocking for about 1 second, the system needs to be designed with non-blocking I/O.

I am using Apache CXF within Play Framework (Java) for this system. I have managed to generate the Asynchronous WS Client proxies and enable the async transport. What I am unable to figure out is how to return a Future to Play's Thread when I have delegated to multiple Web Service proxies and the results will be obtained as callbacks.

Option 1: Using async method calls returning Java Future.

As described in this scala.concurrent.Future wrapper for java.util.concurrent.Future thread, there is no way we can convert a Java Future to a Scala Future. Only way to get a result from the Future is to do Future.get() which blocks the caller. Since CXF's generated proxies return Java Future, this option is ruled out.

Option 2: Use Scala Future.

Since CXF generates the proxy interfaces, I am not sure if there is any way I can intervene and return a Scala Future (AFAIK Akka uses Scala Futures) instead of Java Future?

Option 3: Use the callback approach.

The async methods generated by CXF which return Java Future also takes a callback object which I suppose will provide a callback when result is ready. To use this approach, I will need to return a Future which will wait until I receive a callback.

I think Option 3 is most promising, although I have no ideas about how I can return a Promise which will be completed on receiving a callback. I could possibly have a thread waiting in a while(true) and waiting in between until result is available. Again, I don't know how I can go into wait without blocking the thread?

In a nutshell, I am trying to build a system which is making a lot of SOAP web service calls, where each call blocks for significant time. The system may easily run out of threads in case of lot of concurrent web service calls. I am working on finding a solution which is non-blocking I/O based which can allow many ongoing web service calls at the same time.


回答1:


Option 3 looks good :) A couple of imports to start with...

import scala.concurrent.{Await, Promise}
import scala.concurrent.duration.Duration

and, just to illustrate the point, here's a mocked CXF API that takes the callback:

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

Create a promise, call API with promise as callback:

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

Then you can take promise.future which is an instance of Future into your Play app.

To test it, you can do this:

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

which will block awaiting the result, at which point you should see "results for http://corp/api" in the console.



来源:https://stackoverflow.com/questions/30956704/java-scala-future-driven-by-a-callback

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!