How to block a thread to wait for an answer in vert.x?

I have a situation where I call an external API A and use its response to submit an API B request and call it, and then return a response to the caller of API A. Something like below

method(){ response = call API A } method_for_API_A(){ handler() ->{ API_B } return response; } method_for_API_B(){ //code to call API B } 

What I came across is that the API A method returns a response without waiting for a response from B.

I checked the executeBlocking method for vert.x, and also tried using a "blocking queue", but was unable to achieve what I intend to do. Can someone please guide me to fix the way to do this. Thanks in advance.

EDIT: just to explain the exact scenario

 Class MyClass{ public Response method_A (Request request){ String respFromApiA = Call_API_A(request) ; // STEP 1 Response respFromApiB = Call_API_B(request, respFromApiA); // STEP 2 Print(respFromApiB) // PRINT FINAL Response return respFromApiB; // STEP 3 } String Call_API_A(Request request){ // Implementation Print(string); // PRINT API A response return string } Response Call_API_B(Response response){ // Implementation Print(response); // PRINT API B response return response; } } 

I am using the vert.x framework with Java. Now, what happens at runtime, the thread goes to STEP 1, initiates an API A call. Goes to STEP 2 (without waiting for 'respFromApiA') and calls the API B (which will not work because respFromApiA is NULL). And finally, the thread goes to STEP 3 and returns from here. (without waiting for the results of API A and API B). If we see the print order, it will be something like this

 PRINT FINAL Response PRINT API A response PRINT API B response 

What am I trying to achieve?

 Wait for API A response. Make call to API B. Wait for API B response. Return response got from API B. 

Hope I can do it this time. Please let me know if you need more details.

+5
source share
3 answers

Vert.x is highly asynchronous. Most operations will actually return immediately, but their results will be available to Handler at a later point in time. So far, so good. If I understand you correctly, you need to call B in Handler from A In this case, A needs to be completed, and the result will be available before calling B :

 callA(asyncResultA -> { System.out.println("Result A: " + asyncResultA.result()); callB(asyncResultB -> { System.out.println("Result B:" + asyncResultB.result()); }); }); 

But you are trying to do something asynchronous. You cannot and should not try to make the asynchronous result available in the main program stream - this will not work.

 String respFromApiA = Call_API_A(request); // STEP 1 Response respFromApiB = Call_API_B(request, respFromApiA); // STEP 2 Print(respFromApiB); // PRINT FINAL Response return respFromApiB; // STEP 3 

Call_API_A cannot really return the result because it is evaluated asynchronously. The result is available only for Handler Call_API_A (see My example above). The same goes for Call_API_B - so you cannot return the result of Call_API_B . The caller of your class will also have to call your class using the Handler .

Now add some additional information. In your case, you have a problem that several asynchronous results depend on each other. Vert.x provides a much more convenient way to handle asynchronous results - the so-called Futures . A Future (sometimes called Promise , but in the Java world, which they call Future ), is a placeholder for the results of asynchronous calls. Read about them in the documentation .

With Future you can do something like this:

 Future<...> callAFuture = Future.future(); callA(asyncResultA -> { if (asyncResultA.succeeded()) { System.out.println("A finished!"); callAFuture.complete(asyncResultA.result()); } else { callAFuture.fail(asyncResultA.cause()); } }); 

Therefore, instead of trying to return the asynchronous result of B synchronously, you should return Future so that the class you are calling can register for the asynchronous result of both A and B

Hope this helps.

Edit: Future as return value

Suppose you want to wrap callA so that you can work with Future . You can do it as follows:

 public Future<String> doSomethingAsync() { Future<String> callAFuture = Future.future(); // do the async stuff callA(asyncResultA -> { if (asyncResultA.succeeded()) { System.out.println("A finished!"); callAFuture.complete(asyncResultA.result()); } else { callAFuture.fail(asyncResultA.cause()); } }); // return Future with the asyncResult of callA return callAFuture; } 

A call to this function can use the future as follows:

 Future<String> doSomethingFuture = doSomethingAsync(); doSomethingFuture.setHandler(somethingResult -> { // ... doSomethingAsync finished }); 

It is also possible to make several Future if you want to make them at the same time, but they are not dependent on each other:

 CompositeFuture.all(futureA, futureB).setHandler(connections -> { // both Futures completed }); 

If you are working in an asynchronous environment such as Vert.x, most of the time you are working with the aka Future result file. And in Handler Future you often make another asynchronous call. You wrap Future with Future , like the callB example in the callA Handler .

How would you return an asynchronous Future result as an HTTP response? Like this:

 router.route("/").handler(routingContext -> { HttpServerResponse response = routingContext.response(); Future<String> future = doSomethingAsync(); future.setHandler(somethingResult -> { if (somethingResult.succeeded()) { response .end(somethingResult.result()); } else { routingContext.fail(500); } }); }); 
+11
source

I used Future to return some results , to use it again in other methods, this is my implementation, I hope this helps someone:

  public static void ussdMessages(RoutingContext routingContext){ String codeService = routingContext.getBodyAsJson().getString("codeService"); Future<String> futureQuery=getServiceQuery(codeService); Future<JsonObject> futureParams = getServiceParams(codeService); CompositeFuture.all(futureQuery,futureParams).setHandler(r->{ System.out.println(futureQuery.result()); System.out.println(futureParams.result()); }); } public static Future<JsonObject> getServiceParams(String codeService){ Future<JsonObject> future=Future.future(); JsonObject params = new JsonObject(); params.put("QUERY", Queries.DB_SELECT_SERVICE_PARAMS); params.put("PARAMS", new JsonArray().add(codeService)); DB.select(params, res -> { if (res.succeeded()) { future.complete(res.result()); } else { future.fail(res.cause().getMessage()); } }); return future; } public static Future<String> getServiceQuery(String codeService){ Future<String> future = Future.future(); JsonObject params = new JsonObject(); params.put("QUERY", Queries.DB_SELECT_SERVICE_QUERY); params.put("PARAMS", new JsonArray().add(codeService)); System.out.println(params); DB.select(params, res -> { if (res.succeeded()) { // query = res.result().getJsonArray("results").getJsonArray(0).getString(0); future.complete(res.result().getJsonArray("results").getJsonArray(0).getString(0)); } else { future.fail(res.cause().getMessage()); } }); return future; } 
+1
source

You have three options:

The second is the best solution, as it will be significantly faster, and you can add the C API with minimal effort.

0
source

All Articles