2016-05-13 8 views
5

私は、外部APIのA呼んで状況を持っているとAPI Bの要求に供給し、それを呼び出すと、その後スレッドをブロックしてvert.xでの応答を待つ方法は?

method(){ 
    response = call API A 
    } 

    method_for_API_A(){ 
     handler() ->{ 
     API_B 
     } 
    return response; 
    } 

    method_for_API_B(){ 
    //code to call API B 
    } 

私は以下のようなAPIのA.何かの呼び出し元に応答を返すためにその応答を使用しますここに向いているのはAPIです。メソッドはBからの応答を待たずに応答を返しています。

私はvert.xのexecuteBlockingメソッドについてチェックしましたが、 'blocking queue'を使用しようとしましたが、行う。 誰かがそれをやり遂げる正しい方法を教えてもらえますか?事前に感謝します。

編集:ただ、私は、Javaでフレームワークを使用していますvert.x

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; 
} 

} 

正確なシナリオを説明します。 実行中に何が起こるかは、STEP 1に進み、API Aコールを開始します。 (respFromApiAを待つことなく)ステップ2に進み、API B(respFromApiAがNULLなので最終的に失敗する)を呼び出します。最後に流れはSTEP 3に進み、ここから戻ります。 (API AとAPI Bの結果を待たずに)。 我々は、プリント注文が表示されている場合、それは私が達成しようとしていますこれは何

PRINT FINAL Response 
PRINT API A response 
PRINT API B response 

のようなものでしょうか?

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

今回は明確にできることを願っています。追加の入力が必要な場合はお知らせください。

+0

あなたは両方のコールをしないのはなぜ'メソッド'の中で順番に? – Fildor

+0

ノンブロッキングコールをやっていると思います。彼らはコールバックで回答を返す可能性が最も高いです(私はvert.xを知らない、申し訳ありません)。したがって、それらの呼び出しをブロックし、結果を返すか、コールバックを使用する必要があるかをVert.xに伝える可能性を見つける必要があります。 – Fildor

+0

多分もっと多くのコード(実際のコード)を示したら、vert.xでの経験を持つ人が助けてくれるかもしれません... – Fildor

答えて

0

あなたは3つのオプションがあります。

  1. がAPIに呼び出しを行うと、コールバックでは、APIのB呼び出しを行います。
  2. 両方のapi呼び出しを同時に実行する非同期フレームワーク(https://spring.io/guides/gs/async-method/)を使用します。
  3. 最初と同じですが、約束しています。

それはかなり速くなりますので、第二には、最善の解決策であり、あなたは少しの努力で

+0

私が質問を理解する限り、Param to Callに必要なCall to Bの結果がありますA.したがって、並列呼び出しは実際には意味をなさない。 – Fildor

+0

私はAとBの出力は何かをすると考えていました。多分私の悪い。 –

+0

私は質問のこの部分を参照していました。「私は外部API Aを呼び出し、その応答をAPI Bの要求にフィードする」。たぶん@tausifでこれを少し明確にすることができます。 – Fildor

11

をAPIのCを追加することができVert.xは非常に非同期です。実際にはほとんどの操作は即座に戻りますが、その結果は後でHandlerに送信されます。ここまでは順調ですね。あなたがBHandlerAで電話する必要がある以上に正しく理解している場合。

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

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

しかし、あなたがしようとしていることは何か、非同期シンクロンを作ることです:終了する必要があり、あなたがBを呼び出す前に、結果が利用できるようになるAこの場合、メインプログラムのフローで非同期の結果を利用できるようにすることはできません。そうしないと動作しません。それは非同期に計算されますので、

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は本当に結果を返すことができません。結果は、HandlerCall_API_A(上記の私の例を参照)の場合にのみ利用可能です。 Call_API_Bと同じです。したがって、Call_API_Bの結果を返すことはできません。あなたのクラスの発信者は、Handlerであなたのクラスに電話をする必要があります。

いくつかの追加情報があります。あなたの場合、複数の非同期結果がお互いに依存するという問題があります。 Vert.xは、非同期の結果を処理するためにはるかに便利な方法を提供します - いわゆるFuturesです。 A FuturePromiseと呼ばれることもありますが、Javaの世界ではFutureと呼ばれます)は、非同期呼び出しの結果のプレースホルダーです。 documentationでそれらについて読む。

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

ので、代わりの、あなたのクラスのFutureので、呼び出し先がために登録することができ返す必要があり、同期の方法でBの非同期結果を返すようにしよう:あなたはこのような何かを行うことができFuture

ABの両方の非同期結果

こちらがお役に立てば幸いです。

編集:戻り値

として今後はあなたがFutureで動作することができますので、とcallAをラップしたいとしましょう。あなたはそれをこのように行うことができます:

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; 
} 

をこの関数の呼び出し側は、このように将来を使用することができます。

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

複数Futureを構成することも可能あなたがそれらを同時にやりたいけど、彼らはドン場合お互いに依存して「T:

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

あなたはVert.xのような非同期環境でほとんどの時間を作業する場合、あなたはすぐツー被available- と連携結果別名Futureそして、のHandlerでは、別の非同期呼び出しを行うことがよくあります。 Futureを、callBの例のようなFutureで囲んで、callAHandlerにラップします。

HTTP応答としてFutureの非同期結果をどのように返しますか?このように:

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); 
    } 
    }); 
}); 
+0

ありがとう@Alexvetterは私に答える。私はAPI_AのハンドラーでAPI_Bを呼び出すロジックに同意します。これは私がすでに試したものです。間違いなくクラスの呼び出し側に応答を返そうとしている間違いはハンドラを使って処理する必要があります。 1点をクリアするだけで、最後にAPI_Bの応答を呼び出し側に返さなければなりません。あなたは将来のオブジェクトの使用について述べました。だから私たちは、戻り値の型をFutureとして返し、応答を得るために将来のオブジェクトを呼び出し側に返します。 – tausif

+0

正確には、 'Future'とそのメソッド' setHandler'でちょっと試してみてください。 – alexvetter

+0

Vert.xは高度に非同期なので、アプリケーションは 'Futures'を手渡し、必要に応じてそれらを構成します。イベントループをブロックしないことです! – alexvetter

1

私は他のmethodesで再びそれを使用するために、いくつかのresultsを返すためにFutureを使用している、これは私の実装である私はそれが誰かの役に立てば幸い:

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; 
} 
関連する問題