[英]How to abstract asynchronous HTTP requests as synchronous
I have a third party REST API service that behaves 'asynchronously'; 我有一个第三方REST API服务,行为'异步'; 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'. 回调几乎立即通过“回调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. 我试图设计一个解决方案,一种适配器来调用这个资源,好像它是'同步',因为处理回调是很麻烦的,特别是当我需要通过相同的第三方将连续请求串行批处理到其他类似的API时。 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). 我的研究指向使用RxJava,但我无法弄清楚这个问题如何通过反应式编程的原理来解决(我的理解是有限的)。
Design considerations: 设计注意事项:
How can I employ a CompletableFuture
, or Observable-Observer
pattern to wait for the callback and return to the caller? 如何使用
CompletableFuture
或Observable-Observer
模式等待回调并返回调用者?
Consider using a CountDownLatch
for the main thread to wait until a worker thread has dealt with the third party API. 考虑使用
CountDownLatch
作为主线程,等待工作线程处理第三方API。 The worker gets the callbacks so it knows when the request has made progress, is complete, timed out, had an error, etc. 工作人员获取回调,以便它知道请求何时进展,完成,超时,出错等。
Here's a rough simulation: 这是一个粗略的模拟:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
public class TreatAsSync {
public static void main(String[] args) {
TreatAsSync app = new TreatAsSync();
app.call();
}
private void call() {
RestClient restClient = new RestClient();
Request request = new Request();
Response response = restClient.call(request);
System.out.println("Response was: " + response);
}
private class Request {
}
private class Response {
private final boolean error;
private final boolean timedOut;
private final String result;
public Response(boolean error, boolean timedOut, String result) {
this.error = error;
this.timedOut = timedOut;
this.result = result;
}
public String toString() {
return "error:" + error + ", timedOut: " + timedOut + ", result: " + result;
}
}
private class ResponseWrapper {
private Response response;
public Response getResponse() {
return response;
}
public void setRespose(Response response) {
this.response = response;
}
}
private class RestClient {
public Response call(Request request) {
ResponseWrapper wrapper = new ResponseWrapper();
CountDownLatch latch = new CountDownLatch(1);
ThirdPartyRunner runner = new ThirdPartyRunner(request, wrapper, latch);
new Thread(runner).start();
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return wrapper.getResponse();
}
}
private interface ThirdPartyCallBack {
public void onProgress(Response response);
public void onComplete(Response response);
public void onTimeOut(Response response);
public void onError(Response response);
}
private class ThirdPartyRunner implements ThirdPartyCallBack, Runnable {
private final Request request;
private final ResponseWrapper wrapper;
private final CountDownLatch latch;
public ThirdPartyRunner(Request request, ResponseWrapper wrapper, CountDownLatch latch) {
this.request = request;
this.wrapper = wrapper;
this.latch = latch;
}
@Override
public void onProgress(Response response) {
System.out.println("some progress was made...");
}
@Override
public void onComplete(Response response) {
System.out.println("request completed");
finished(response);
}
@Override
public void onTimeOut(Response response) {
System.out.println("request timed out");
finished(response);
}
@Override
public void onError(Response response) {
System.out.println("request had an error");
finished(response);
}
private void finished(Response response) {
wrapper.setRespose(response);
latch.countDown();
}
@Override
public void run() {
try {
callThirdParty();
} catch (Exception e) {
finished(new Response(true, false, e.getMessage()));
}
}
private void callThirdParty() {
// simulate api.call(request, this);
for (int i = 0; i < ThreadLocalRandom.current().nextInt(10) + 1; i++) {
onProgress(new Response(false, false, "in progress"));
}
switch (ThreadLocalRandom.current().nextInt(3)) {
case 0:
onComplete(new Response(false, false, "done"));
break;
case 1:
onTimeOut(new Response(false, true, "hello?"));
break;
case 2:
onError(new Response(true, false, "uh oh!"));
break;
}
}
}
}
If you have this: 如果你有这个:
public ImmediateResponse asynchCall(Callback callback) throws ImmediateException {...}
Where Callback
looks like this: Callback
看起来像这样:
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());
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.