Listen to 2 calls of async webservice without using AsyncResult

Play 2 allows you to make asynchronous webservice calls through AsyncResult, which will not block the stream:

public static Result feedTitle(String feedUrl) { return async( WS.url(feedUrl).get().map( new Function<WS.Response, Result>() { public Result apply(WS.Response response) { return ok("Feed title:" + response.asJson().findPath("title")); } } ) ); } 

This only works if you do simple things, for example, passing the result of a WS call directly to the user. However, what if you need to perform additional operations on the result?

After looking at the documentation , it looks like you can do this:

 Promise<Response> promise = WS.url("http://some.website.com").get(); Response response = promise.get(); // I've got the result, but I've also blocked 

This is obviously not perfect. Is there a way to make asynchronous calls by letting Play pass execution to other threads?

+4
source share
4 answers

Take a look at https://github.com/jroper/play-promise-presentation . This really clarified the question for me on how to create a system that could have several promises on a call, etc., and manipulate various answers to the promise in what is needed for a more complex answer, etc.

The best part is the example is not too verbose. It reads very well and is pretty clear.

+1
source

Ok, I found a solution, albeit a bit detailed. What you can do is move everything to the actor.

Set up your Actor in your global object, but save the ActorRef somewhere that you can access.

 ActorRef myActor = Akka.system().actorOf(new Props(MyActor.class)); 

In your Actor, make a WS call.

 public void onReceive(Object message) { WSRequestHolder request = WS.url("http://example.com"); Response response = request.get().get(); SomeResult result = doFurtherProcessing(response); getContext().sender().tell(result); // reply the asking thread } 

And in your controller, just wrap the call to your actor in async ()

 public static Result method() { String message = "hello"; return async( Akka.asPromise(ask(myActor, message, 1000)).map(new Function<Object, Result>() { public Result apply(Object result) throws Throwable { return ok(result); } }) ); } 

Link: http://www.playframework.org/documentation/2.0.3/JavaAkka

0
source

There is no need to create actors only to defer calculations. You can bind post processing to asynchronous calls using Promise.map(Function<A, B>) and Promise.flatMap(Function<<A>, Promise<B>>) . These challenges are connected.

Example:

 return async(WS.url("http://someservice.com/").get().map( new F.Function<play.libs.WS.Response, SomeData>() { @Override public SomeData apply (play.libs.WS.Response response) throws Throwable { SomeData someData = computeData(response); // Do extra computing here return someData; } }).map( new F.Function<SomeData, Result>() { @Override public Result apply(SomeData someData) throws Throwable { Result result = doSomethingElse(someData); return ok(result); } }) ); 

As long as the last map returns a Result , you're good to go.

0
source

Alternative answer for play2

 String url1 = String.format( "http://localhost:8080/site1", langcode ); String url2 = String.format( "http://localhost:8080/site2", langcode ); String url3 = String.format( "http://localhost:8080/site3", langcode ); F.Promise<WS.Response> remoteCall1 = WS.url(url1).get(); F.Promise<WS.Response> remoteCall2 = WS.url(url2).get(); F.Promise<WS.Response> remoteCall3 = WS.url(url3).get(); F.Promise<java.util.List<WS.Response>> promisesSequence = F.Promise.sequence(remoteCall1, remoteCall2, remoteCall3); F.Promise<Result> resultPromise = promisesSequence.map( new Function<java.util.List<WS.Response>, Result>(){ @Override public Result apply(java.util.List<WS.Response> responses){ final StringBuffer sb = new StringBuffer(); for(WS.Response r : responses){ sb.append(r.getBody()); } return ok( main.render("Output", sb.toString())); } }); 
0
source

All Articles