如何阻止线程等待 vert.x 中的响应?
How to block thread to wait for response in vert.x?
我有一种情况,我调用外部 API A 并使用它的响应来响应 API B 的请求并调用它,然后 return 对调用者的响应API A. 如下所示
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 方法是 returning 响应而不等待 B 的响应。
我检查了 vert.x 的 executeBlocking 方法,也尝试使用 'blocking queue' 但无法实现我的意图。
有人可以提前指导我正确的做法 it.Thanks 吗?
编辑:只是为了解释确切的场景
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;
}
}
我正在使用 vert.x 框架和 Java。
现在执行期间发生的事情是,流程来到第 1 步,发起 API 调用。转到步骤 2(不等待 'respFromApiA')并调用 API B(最终失败,因为 respFromApiA 为 NULL)。最后流程从这里转到第 3 步和 return。 (无需等待 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.
希望这次能说清楚。如果您需要进一步的输入,请告诉我。
您有三个选择:
- 执行 API A 调用并在回调中执行 API B 调用。
- 使用您选择的异步框架 (https://spring.io/guides/gs/async-method/),这将 运行 两个 api 并行调用。
- 与第一个相同,但有承诺。
第二个是最好的解决方案,因为它会快得多,而且您可以毫不费力地添加 API C
Vert.x 是高度异步的。大多数操作实际上会立即 return 但它们的结果将在稍后的某个时间点提供给 Handler
。到目前为止,一切都很好。如果我理解正确的话,你需要在 A
的 Handler
中调用 B
。在这种情况下,A
需要完成,结果在您调用 B
:
之前可用
callA(asyncResultA -> {
System.out.println("Result A: " + asyncResultA.result());
callB(asyncResultB -> {
System.out.println("Result B:" + asyncResultB.result());
});
});
但是你正在尝试的是让一些东西异步同步。您不能也不应该尝试在主程序流程中提供异步结果——那是行不通的。
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
不能真正 return 结果,因为它是异步计算的。结果仅适用于 Call_API_A
的 Handler
(参见我上面的示例)。 Call_API_B
也是如此——所以你不能 return Call_API_B
的结果。 class 的来电者还需要使用 Handler
.
来呼叫您的 class
现在补充一些信息。在您的情况下,您会遇到多个异步结果相互依赖的问题。 Vert.x 提供了一种更方便的方式来处理异步结果——即所谓的 Futures
。 Future
(有时称为 Promise
但在 Java 世界中它们称为 Future
)是异步调用结果的占位符。在 documentation.
中了解它们
有了 Future
你可以这样做:
Future<...> callAFuture = Future.future();
callA(asyncResultA -> {
if (asyncResultA.succeeded()) {
System.out.println("A finished!");
callAFuture.complete(asyncResultA.result());
} else {
callAFuture.fail(asyncResultA.cause());
}
});
因此,与其尝试以同步方式 return B
的异步结果,不如 return 一个 Future
这样 [=85= 的被调用方] 可以注册 A
和 B
.
的异步结果
希望对您有所帮助。
编辑:未来作为 return 值
假设您想用 callA
包装起来,这样您就可以使用 Future
。你可以这样做:
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:
Future<String> doSomethingFuture = doSomethingAsync();
doSomethingFuture.setHandler(somethingResult -> {
// ... doSomethingAsync finished
});
也可以组成多个 Future
如果你想同时做它们但它们不相互依赖:
CompositeFuture.all(futureA, futureB).setHandler(connections -> {
// both Futures completed
});
如果你在像 Vert.x 这样的异步环境中工作,大部分时间你会使用 即将可用的结果 又名 Future
.在 Future
的 Handler
中,您经常会进行另一个异步调用。你用 Future
包裹 Future
就像 callA
的 Handler
.
中 callB
的例子
如何将 return Future
的异步结果作为 HTTP 响应?像这样:
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);
}
});
});
我已经使用 Future
到 return 一些 results
在其他方法中再次使用它,这是我的实现我希望它能帮助别人 :
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;
}
我有一种情况,我调用外部 API A 并使用它的响应来响应 API B 的请求并调用它,然后 return 对调用者的响应API A. 如下所示
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 方法是 returning 响应而不等待 B 的响应。
我检查了 vert.x 的 executeBlocking 方法,也尝试使用 'blocking queue' 但无法实现我的意图。 有人可以提前指导我正确的做法 it.Thanks 吗?
编辑:只是为了解释确切的场景
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;
}
}
我正在使用 vert.x 框架和 Java。 现在执行期间发生的事情是,流程来到第 1 步,发起 API 调用。转到步骤 2(不等待 'respFromApiA')并调用 API B(最终失败,因为 respFromApiA 为 NULL)。最后流程从这里转到第 3 步和 return。 (无需等待 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.
希望这次能说清楚。如果您需要进一步的输入,请告诉我。
您有三个选择:
- 执行 API A 调用并在回调中执行 API B 调用。
- 使用您选择的异步框架 (https://spring.io/guides/gs/async-method/),这将 运行 两个 api 并行调用。
- 与第一个相同,但有承诺。
第二个是最好的解决方案,因为它会快得多,而且您可以毫不费力地添加 API C
Vert.x 是高度异步的。大多数操作实际上会立即 return 但它们的结果将在稍后的某个时间点提供给 Handler
。到目前为止,一切都很好。如果我理解正确的话,你需要在 A
的 Handler
中调用 B
。在这种情况下,A
需要完成,结果在您调用 B
:
callA(asyncResultA -> {
System.out.println("Result A: " + asyncResultA.result());
callB(asyncResultB -> {
System.out.println("Result B:" + asyncResultB.result());
});
});
但是你正在尝试的是让一些东西异步同步。您不能也不应该尝试在主程序流程中提供异步结果——那是行不通的。
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
不能真正 return 结果,因为它是异步计算的。结果仅适用于 Call_API_A
的 Handler
(参见我上面的示例)。 Call_API_B
也是如此——所以你不能 return Call_API_B
的结果。 class 的来电者还需要使用 Handler
.
现在补充一些信息。在您的情况下,您会遇到多个异步结果相互依赖的问题。 Vert.x 提供了一种更方便的方式来处理异步结果——即所谓的 Futures
。 Future
(有时称为 Promise
但在 Java 世界中它们称为 Future
)是异步调用结果的占位符。在 documentation.
有了 Future
你可以这样做:
Future<...> callAFuture = Future.future();
callA(asyncResultA -> {
if (asyncResultA.succeeded()) {
System.out.println("A finished!");
callAFuture.complete(asyncResultA.result());
} else {
callAFuture.fail(asyncResultA.cause());
}
});
因此,与其尝试以同步方式 return B
的异步结果,不如 return 一个 Future
这样 [=85= 的被调用方] 可以注册 A
和 B
.
希望对您有所帮助。
编辑:未来作为 return 值
假设您想用 callA
包装起来,这样您就可以使用 Future
。你可以这样做:
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:
Future<String> doSomethingFuture = doSomethingAsync();
doSomethingFuture.setHandler(somethingResult -> {
// ... doSomethingAsync finished
});
也可以组成多个 Future
如果你想同时做它们但它们不相互依赖:
CompositeFuture.all(futureA, futureB).setHandler(connections -> {
// both Futures completed
});
如果你在像 Vert.x 这样的异步环境中工作,大部分时间你会使用 即将可用的结果 又名 Future
.在 Future
的 Handler
中,您经常会进行另一个异步调用。你用 Future
包裹 Future
就像 callA
的 Handler
.
callB
的例子
如何将 return Future
的异步结果作为 HTTP 响应?像这样:
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);
}
});
});
我已经使用 Future
到 return 一些 results
在其他方法中再次使用它,这是我的实现我希望它能帮助别人 :
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;
}