I have a third party REST API service that behaves 'asynchronously'; as in requests respond with intermediate responses that are supplemented by callbacks with a correlator to the intermediate response.
The callbacks are returned almost immediately via a 'callback URL'.
I am trying to devise a solution, sort of an adapter to call this resource as though it was 'synchronous' because it is cumbersome to deal with the callbacks, especially when I need to batch successive requests serially to other similar APIs by the same thirdparty. Basically I want to abstract the green part so that the caller only gets full callback, an error or timeout exception.
My research points at using RxJava but I can't figure out how this problem can be solved by principles of reactive programming(my understanding is limited).
Design considerations:
- Persisting correlator to a datastore for later lookup upon callback is not desirable because it is expensive
- Wait strategy for the callback is OK because the response times for the callback is less than 1 sec
How can I employ a CompletableFuture
, or Observable-Observer
pattern to wait for the callback and return to the caller?
If you have this:
public ImmediateResponse asynchCall(Callback callback) throws ImmediateException {...}
Where Callback
looks like this:
interface Callback {
void onSuccess(EventualResponse eventualResponse);
void onFailure(Exception e);
}
Then what you want is something like this:
public static EventualResponse synchCall(long timeout, TimeUnit timeUnit)
throws InterruptedException, TimeoutException, EventualException
{
CompletableFuture<EventualResponse> responseFuture = new CompletableFuture<>();
Callback callback = new Callback() {
public void onSuccess(EventualResponse response) {
responseFuture.complete(response);
}
public void onFailure(Exception e) {
responseFuture.completeExceptionally(e);
}
};
try {
/*ImmediateResponse immediateResponse = */asynchCall(callback);
// use immediateResponse if you need it
return responseFuture.get(timeout, timeUnit);
} catch (ImmediateException e) {
throw new EventualException(e);
} catch (ExecutionException ee) {
throw new EventualException(ee.getCause());
}
}