JDev
JDev

Reputation: 1822

Java: How to handle an API call that can take around 10 seconds

I have a requirement and I am bit confused about its design.

Requirement: iOS makes a call to backend(java), backend makes a call to the cloud API which return a token for future calls. The cloud API might take approximately 6 to 10 seconds to return the actual result, so instead of waiting for 6 to 10 seconds it gives a token back and let the caller(in my case the backend java server) to pull the results.

Current Approach: iOS calls the backend(java server), the backend calls cloud API and get's the token, then it sleeps the thread for 1 second and once the thread is invoked it hit the cloud API to get the status, if the status is not completed thread.sleep is invoked again and this continues till the cloud API call give's the complete result. Once the cloud API returns the result the backend returns the result to iOS.

The approach is not scalable and was done to test the cloud API but now we need a more scalable approach.

This is what I am thinking about iOS calls backend, backend calls the API and send back the result to iOS(it displays some static screen just to keep users engaged) and in the mean time it puts the object in Spring Thread pool Executor. The executor hits the API every one second and update the iOS through push notification and this continues till we get the final result from cloud API.

This is better then existing approach but even this doesn't look scalable and thread pool executor will get exhausted after some time(making it slow) and also thread.sleep is also not a good option.

I thought about using AWS SQS but it doesn't provide real time processing and running background jobs every 1 second doesn't seem to be a good option.

I am also exploring Apache Kafka and trying to understand whether it can fit to my use case.

Let me know if someone has tacked the similar kind of use case.

Upvotes: 1

Views: 1587

Answers (2)

JDev
JDev

Reputation: 1822

I am thinking about using Spring ConcurrentTaskExecutor(let's call it cloudApiCall) and as soon as I received the token from Cloud API, I will submit a future job to the executor and return the token to the Mobile Client. The thread associated with ConcurrentTaskExecutor will pick the job, call the Cloud API and submit the response to the another ConcurrentTaskExecutor(let's call it pushNotification) which will be responsible for pushing the silent notification to the Mobile client. The thread associated ConcurrentTaskExecutor(cloudApiCall), will also check the status of the call, if the future call is required, it will submit the job back to ConcurrentTaskExecutor(cloudApiCall). This will continue till we get the complete response.

Upvotes: 0

Ammar
Ammar

Reputation: 4024

Here @EventListener in tandem with @Scheduled can be utilized, if Spring 4.2 (or newer) version is used.

First Create an event object say APIResult which will hold the API result

public class APIResult extends ApplicationEvent {   
    public APIResult(Object result) { 
        super(source);      
    } 
}

Next register a listener for the event published as APIResult

@Component
public class MyListener {

    @EventListener
    public void handleResult(APIResult result) {
       // do something ... 
    }
}

Next create a scheduled process which will hold the token(s) for which result is not yet retrieved

@Component
public class MyScheduled {

    private final ApplicationEventPublisher publisher;

    private List<String> tokens = new ArrayList<>();    

    @Autowired
    public MyScheduled (ApplicationEventPublisher publisher) { 
        this.publisher = publisher;
    }

    @Scheduled(initialDelay=1000, fixedRate=5000) // modify it as per requirement
    public void callAPIForResult() {
        // call the API and get result for each token(s) ....
        this.publisher.publishEvent(new APIResult(result)); 
    }

    // method to add & remove tokens
}

The overall process flow should be like

  1. Application submit a request to API and collect the respective token.
  2. Token is passed to scheduled service to fetch the result.
  3. In its next run the scheduled service iterates over the available token(s) and call API to fetch the results (if result is available publish the event else continue)
  4. The published event is intercepted by registered listener; which itself process the result or delegates as applicable

This approach will transparently fetch results without messing with the business logic and at same time leveraging the standard framework features viz. scheduling and asynchronous event publishing & processing.

Although I have not tested this but it should work, at least giving an idea on how to implement. The setup is tested with Spring boot ver. 1.5.1.RELEASE which is backed by Spring's 4.3.6.RELEASE

Do let know in comments if any further information is required.

Reference - Application Event in Spring (link)

Upvotes: 1

Related Questions