简体   繁体   中英

Synchronizing asynchronous API calls with Java

Consider the following scenario:

  1. Service A calls service B in order to get a task done.
  2. Service B returns "OK", and proceeds in order to perform the task asynchronously.
  3. Since A received OK from B, it also returns a response to whoever called it.

I want to be able to synchronize this task. Service B is customizable so that it can make an API call by the end of the task its supposed to do. My idea is:

  1. Service A calls service B in order to get a task done.
  2. Service B returns "OK", and proceeds in order to perform the task asynchronously.
  3. Service A receives the response from B, but does not return.
  4. Service B ends the task, and sends an API call to A (to a certain endpoint, etc...).
  5. Service A receives then returns.

This is just an example. In fact, service A is a Spring boot application, while service B is a third-party software we are building on top of.

Is it possible to synchronize an asynchronous API call like so with Java/Spring? I tried searching online for this but could not find anything suitable.

So depending on what your request data looks like, I am going to assume that there is a unique id that is sent from Service A to Service B.

If that is the case, you can use this id as a correlation id and could implement a waiting strategy using CompletableFutures. When service B responds with the "OK", Service A can create a completable future using the unique ID as a key and call get() on this, which will block until complete() is called. When Service B is finished with its processing, it can invoke an API on Service A with the result, along with the correlation id, which can now be used to complete the future.

The below is some basic code just to illistrate the idea

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

However, using this type of approach, there are a number of things to take into consideration like what to do if Service B never actually calls back to Service A with a result, or rather if you timeout waiting for Service B to respond, remove the future, and then the response comes back at a later stage, what should you do to handle this?

But this is now all down to what your Service A does, and what your specific cases are around failure, ie storing the state of requests in Service A, and providing a mechanism for querying a state etc..

I would highly recommend however, depending on the flexibility of your project, to look into a middleware queuing mechanisms be that RabbitMQ/Kafka/Pulsar etc as they all provide great functionalities for work queue based architectures and could provide useful for you depending on your situation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM