当前位置: 首页 > 知识库问答 >
问题:

异步HTTP后重试并在最大重试次数后排气

郑向阳
2023-03-14
// calls post
public void call(String data) throws CustomException {
    
    asyncHttpClient.post(data, 10);

}
// 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块。
...
} catch (ExecutionException e) {
    // ConnectionException
    // RequestTimeoutException
    sleep(10); // 10 seconds
    try {
        post(data, retry - 1);
    } catch (CustomException e) {
    }
}
...

共有1个答案

彭胡媚
2023-03-14

好吧,所以试图用代码重现您想要实现的功能,但立即意识到CustomException只有在类型为RuntimeException时才有效。原因是您希望在运行时和另一个线程中抛出异常。

下面的代码显示了该异常的简单实现。请记住,并非所有的RuntimeException都会停止程序。这将在本线程中解释。所以如果你想终止程序,你必须手动停止它。

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()方法,该方法等待请求完成。但是由于我是在一个单独的线程中执行所有这些,所以它应该在后台而不是主线程中运行。

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

}
java prettyprint-override">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);
}
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);
        }
}
 类似资料:
  • 问题内容: 我有一个以开头的循环。正常情况下,它可以正常运行,但有时由于网络条件而失败。目前,我已对其进行了设置,以便在失败时,它将在except子句中(继续到的下一个数字)。 我是否可以将相同的数字重新分配给循环并再次执行失败的循环? 问题答案: 做一个内部的for循环,把你的代码中,并突破从只有当你的代码的成功循环。

  • 我有一个调用外部应用程序的Restful服务。这个应用程序使我的服务挂起。因此,当用户调用我的服务时,由于这个外部应用程序,可能需要一个小时。外部应用程序只需几秒钟即可执行。否则,就出了问题。因此,我希望我的服务中的代码最多执行30秒。如果超过30秒,我想停止服务并重新启动它。 以下是我想要的: 我不希望代码每30秒执行一次。我希望能够停止代码执行,并从头重新启动它。 服务内容如下:

  • 我有一个异步块: 我可以跟踪成功和失败的结果。但是,是否可以重试整个chain?然后继续重试,直到问题解决?

  • 转换为任务返回委托的异步lambda表达式不能返回值

  • Apollo link提供了一个错误处理程序 问题:目前,我们希望在apollo调用期间过期时刷新oauth令牌,并且我们无法在中正确执行异步获取请求。 代码: <代码>初始化阿波罗客户端。js 发生的情况是: 初始图形QL查询运行并因未经授权而失败 执行的函数。 刷新令牌的promise已执行。 再次执行的函数?? 刷新令牌的promise完成。 返回初始的graph QL查询结果,其数据为 在

  • 我将JBoss EAP 6.3应用服务器与JDG 6.3.1(使用Infinispan 6.1.2)结合使用,这两个实例都运行在同一个虚拟机上,连接协议是Hot Rod。 如果由于任何原因无法访问JDG,我希望EAP上EJB应用程序中使用的Hot Rod客户端捕捉HotRodClientException,并直接继续进行数据库调用。这可以正常工作,但RemoteCacheManager中的重试次数