首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >异步HTTP post重试和最大重试后的耗尽

异步HTTP post重试和最大重试后的耗尽
EN

Stack Overflow用户
提问于 2020-09-24 05:56:59
回答 3查看 2.2K关注 0票数 2

在多次异步请求调用失败后,我如何完成重试?我正在使用AsyncHttpClient向我们的服务器发送请求。在请求超时、连接异常等情况下,我希望客户端重试N次并抛出自定义异常。调用方法应接收此异常,否则将无法处理。

代码语言:javascript
运行
复制
// calls post
public void call(String data) throws CustomException {
    
    asyncHttpClient.post(data, 10);

}
代码语言:javascript
运行
复制
// posts data to http endpoint
public void post(String data, int retries) throw CustomException {
    // if retries are exhausted, throw CustomException to call()
    if (retry <= 0) {
        throw new CustomException("exc");
    }

    BoundRequest request = httpClient.preparePost("http_endpoint");
    ListenableFuture<Response> responseFuture = httpClient.post(request);
 
    responseFuture.addListener(() -> {
        Response response = null;
        int status = 0;
        try {

            response = responseFuture.get();
            status = response.getStatusCode();

            // HTTP_ACCEPTED = {200, 201, 202}
            if (ArrayUtils.contains(HTTP_ACCEPTED, status)) {
                // ok
            } else {
                sleep(10);
                post(data, retry - 1);
            }
        } catch (InterruptedException e) {
            sleep(10);
            post(data, retry - 1);

        } catch (ExecutionException e) {
            // ConnectionException
            // RequestTimeoutException
            sleep(10); // 10 seconds
            post(data, retry - 1);
        } catch (Exception e) {
            sleep(10); // 10 seconds
            post(data, retry - 1 );
        } finally {
            responseFuture.done();
        }
    },  Runnable::run);

} 

这种方法有几个问题:

  1. 使用递归调用重试。
  2. CustomException似乎从未抛出,在重试== 0之后,控件返回到finally块。
代码语言:javascript
运行
复制
...
} catch (ExecutionException e) {
    // ConnectionException
    // RequestTimeoutException
    sleep(10); // 10 seconds
    try {
        post(data, retry - 1);
    } catch (CustomException e) {
    }
}
...
EN

回答 3

Stack Overflow用户

发布于 2020-09-30 04:30:23

AsyncHttpClient中有一个预定义函数来处理MaxRetries,

下面的代码显示了一个简单的实现

代码语言:javascript
运行
复制
AsyncHttpClientConfig cf = new DefaultAsyncHttpClientConfig.Builder().setMaxRequestRetry(5).setKeepAlive(true).build()
final AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient(cf);

您可以删除您的重试逻辑,让AsyncHttpClient处理相同的逻辑。

票数 3
EN

Stack Overflow用户

发布于 2020-09-27 15:06:53

好的,所以试着用代码复制您想要实现的目标,但是立即意识到,只有当CustomExceptionRuntimeException类型时,它才能工作。原因是您希望在运行时和在另一个线程中抛出异常。

下面的代码显示了异常的简单实现。请记住,并非所有的RuntimeExceptions都停止程序。在这个线程中解释了这一点。因此,如果您想终止程序,您必须手动停止它。

代码语言:javascript
运行
复制
public class CustomException extends RuntimeException {

    public CustomException(String msg) {
        super(msg);
        // print your exception to the console
 
        // optional: exit the program
        System.exit(0);
    }

}

我更改了剩下的实现,这样您就不必再进行递归调用了。我删除了回调方法,而是调用了get()方法,该方法等待请求完成。但是由于我是在一个单独的线程中执行所有这些,所以它应该在后台运行,而不是在主线程中运行。

代码语言:javascript
运行
复制
public class Main {

    private final AsyncHttpClient httpClient;
    private final int[] HTTP_ACCEPTED = new int[]{200, 201, 202};

    private final static String ENDPOINT = "https://postman-echo.com/post";

    public static void main(String[] args) {
        String data = "{message: 'Hello World'}";
        Main m = new Main();
        m.post(data, 10);

    }

    public Main() {
        httpClient = asyncHttpClient();
    }

    public void post(final String data, final int retry) {

        Runnable runnable = () -> {
            int retries = retry;

            for (int i = 0; i < retry; i++) {
                Request request = httpClient.preparePost(ENDPOINT)
                        .addHeader("Content-Type", "application/json")
                        .setBody(data)
                        .build();

                ListenableFuture<Response> responseFuture = httpClient.executeRequest(request);
                try {
                    Response response = responseFuture.get();
                    int status = response.getStatusCode();

                    if (ArrayUtils.contains(HTTP_ACCEPTED, status)) {
                        System.out.println("Successful! Breaking Loop");
                        break;
                    } else {
                        Thread.sleep(10);
                    }

                } catch (InterruptedException | ExecutionException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
                retries--;
            }

            System.out.println("Remaining retries: " + retries);

            if (retries <= 0) {
                throw new CustomException("exc");
            }
        };

        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.submit(runnable);
    }

}

替代方案

您可以使用相同的Runnable进行异步调用,而不必等待future.get()。每个侦听器将在同一个线程中方便地被调用,这使得它对于您的用例更有效。

代码语言:javascript
运行
复制
public void post2(final String data, final int retry) {
        Request request = httpClient.preparePost(ENDPOINT)
                .addHeader("Content-Type", "application/json")
                .setBody(data)
                .build();

        ListenableFuture<Response> future = httpClient.executeRequest(request);

        MyRunnable runnable = new MyRunnable(retry, future, request);
        future.addListener(runnable, null);
}
代码语言:javascript
运行
复制
public class MyRunnable implements Runnable {

        private int retries;
        private ListenableFuture<Response> responseFuture;
        private final Request request;

        public MyRunnable(int retries, ListenableFuture<Response> future, Request request) {
            this.retries = retries;
            this.responseFuture = future;
            this.request = request;
        }

        @Override
        public void run() {

            System.out.println("Remaining retries: " + this.retries);
            System.out.println("Thread ID: " + Thread.currentThread().getId());


            try {
                Response response = responseFuture.get();
                int status = response.getStatusCode();

                if (ArrayUtils.contains(HTTP_ACCEPTED, status)) {
                    System.out.println("Success!");
                    //do something here

                } else if (this.retries > 0) {
                    Thread.sleep(10);
                    this.execute();
                } else {
                    throw new CustomException("Exception!");
                }

            } catch (InterruptedException | ExecutionException e) {
                this.execute();
            }
        }

        private void execute() {
            this.retries -= 1;
            this.responseFuture = httpClient.executeRequest(this.request);
            this.responseFuture.addListener(this, null);
        }
}
票数 2
EN

Stack Overflow用户

发布于 2020-10-03 17:49:50

在某些情况下,许多人希望抛出新的RuntimeException (ee),而不是抛出e。

代码语言:javascript
运行
复制
catch (ExecutionException e) {
    Throwable ee = e.getCause ();

    if (ee instanceof InvalidInputException)
    {
        //error handling 1
    } else if (ee instanceof MiscalculationException e)
    {
        //error handling 2
    }
    else throw e; // Not ee here
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64040323

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档