与 Java 同步异步 API 调用

Gab*_*ina 4 java asynchronous synchronous spring-boot

考虑以下场景:

  1. 服务 A 调用服务 B 来完成任务。
  2. 服务 B 返回“OK”,并继续异步执行任务。
  3. 由于 A 收到了来自 B 的 OK,因此它也会向调用它的人返回响应。

我希望能够同步此任务。服务 B 是可定制的,因此它可以在其应该执行的任务结束时进行 API 调用。我的想法是:

  1. 服务 A 调用服务 B 来完成任务。
  2. 服务 B 返回“OK”,并继续异步执行任务。
  3. 服务 A 收到 B 的响应,但没有返回。
  4. 服务 B 结束任务,并向 A 发送 API 调用(到某个端点等)。
  5. 服务A接收然后返回。

这只是一个例子。事实上,服务 A 是一个 Spring boot 应用程序,而服务 B 是我们在其上构建的第三方软件。

是否可以使用 Java/Spring 同步异步 API 调用?我尝试在网上搜索此内容,但找不到任何合适的内容。

Bre*_*all 5

因此,根据您的请求数据的样子,我将假设有一个从服务 A 发送到服务 B 的唯一 ID。

如果是这种情况,您可以使用此 id 作为相关 id,并可以使用 CompletableFutures 实现等待策略。当服务 B 响应“OK”时,服务 A 可以使用唯一 ID 作为密钥创建一个可完成的 future,并在此调用 get(),这将阻塞,直到调用complete()。当服务 B 完成其处理时,它可以使用结果以及相关 ID 调用服务 A 上的 API,现在可以使用该结果来完成未来的工作。

下面是一些基本代码只是为了说明这个想法

public class ServiceA {

    private Map<String, CompletableFuture<String>> correlationStore;

    public ServiceA() {
        correlationStore = new HashMap<>();
    }

    public String performTask(String id, String data) {

        CompletableFuture<String> futureResult = new CompletableFuture<>();
        String submissionResult = callServiceB(id, data);
        if (!"OK".equalsIgnoreCase(submissionResult)) {
            return "FAILED";
        }
        //Service B has accepted the request and is busy processing the result
        correlationStore.put(id, futureResult);
        String response = null;
        try {
            //Set a timeout to whatever is sensible
            response = futureResult.get(30, TimeUnit.SECONDS); // Thread is now blocked until complete() is called
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            if (e instanceof TimeoutException) {
                correlationStore.remove(id);
            }
            //Handle failure depending on your requirements
        }
        return response;
    }

    //This is called from API call back from Service B
    public void onResponse(String id, String responseData) {
        CompletableFuture<String> pendingResult = correlationStore.remove(id);
        if (pendingResult != null) {
            pendingResult.complete(responseData);
        } else {
            //Handle the scenario where there is not future waiting for a response
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,使用这种类型的方法时,有很多事情需要考虑,例如如果服务 B 从未实际回调服务 A 并返回结果该怎么办,或者如果您超时等待服务 B 响应,请删除未来,然后稍后才返回响应,您应该如何处理?

但这现在完全取决于您的服务 A 所做的事情,以及您的具体情况是围绕失败的,即将请求的状态存储在服务 A 中,并提供查询状态的机制等。

然而,我强烈建议,根据您项目的灵活性,研究中间件排队机制,例如 RabbitMQ/Kafka/Pulsar 等,因为它们都为基于工作队列的架构提供了强大的功能,并且可以根据您的情况为您提供有用的功能。