发送http请求出现异常,怎样设置重试? 例如出现异常后 间隔30秒 3分钟 3小时 重试三次.

发布于 2022-09-12 22:15:44 字数 242 浏览 56 评论 0

问题描述

java编程相关: 发送http请求出现异常,怎样设置重试机制?

问题出现的环境背景及自己尝试过哪些方法

1.使用for循环,通过try catch , 但是这样会一直占用一个线程的资源.

你期待的结果是什么?实际看到的错误信息又是什么?

现在有个想法是 把请求放入消息队列中,然后设置延时等级. 如果第二次重试再次失败,就把延时等级提高 ~ 不知道是否可行,或者有没有更好的解决方法.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

掩于岁月 2022-09-19 22:15:44

消息队列确实是ok的,毕竟题主的需求来看无碍乎就是一个循环的重试,重试间隔需要指定,所以用延迟消息队列绝对能够解决问题,消息队列中间件选择很多

BaLaLaLs提到的rabbitmq确实需要一个插件来做,也可以选择RocketMQ,天生支持延迟消息,当然用redis去模拟一种延迟效果也是可以的

不过以上方案的选型,感觉需要额外多部署一些东西,假如系统之前并没有这方面的中间件,那可能为了做一个重试方案,显得有点大材小用了,毕竟确实真要实现,简单的循环,加上一些if判断就搞定了(至于占用线程资源倒是小事了),只是说这样的代码比较难看,而且也无法复用

我记得在Java轮子百宝屋Spring中,有一个工程:Spring Batch,这里面有一个重试的注解@Retryable,去看了一下,这一套API现在已经独立出来,名叫:Spring-Retry

简单的@Retryable注解配置就可以让一个方法直接具有重试效果(即使我不解释注解属性的含义,也应该能简单看懂重试规则)
image.png

执行该方法的效果
image.png

可以看到很简单就配置好了一套按照倍数增长间隔时间的重试方案

当然可以玩出很多效果,题主可以自己探索,但是为了解决题主的问题,我还是提前玩了一下,先说结论:
我自己反正试过已经有的API还不能支持题主30秒,3分钟,3小时的配置(或许我眼瞎没看到。。。)。毕竟他们之间的倍数没有特定的递增关系,可以看作是直接配置死了几次重试的间隔而已

由于注解@Retryable的实现重试的方式是按照已有的Spring-Retry配置的策略,所以我们得使用Spring-Retry提供的另一种方式去定制一个重试模版

先简单介绍一下,@Retryable的实现方式其实是基于一个拦截器的AnnotationAwareRetryOperationsInterceptor,而拦截器里面会去为被注解的方法创建一个RetryTemplate,这个RetryTemplate中包含了注解中的规则以及被注解的方法

所以定制重试模版的方式其实就是我们自己定义一个RetryTemplate,然后自己定义规则

先说规则,因为我们只是为了把一列间隔时间直接取出来然后重试,所以我们的规则就很简单,实现类CustomBackOffPolicy(以下截图并不是完整代码)
image.png

用一个Queue<Long> intervalQueue的方式简单粗暴的存储间隔时间,在需要取间隔时间直接调用poll方法,取队列首位并删除

然后我们就可以自定义RetryTemplate,间隔时间分别为1秒,5秒,10秒,其中SimpleRetryPolicySpring-Retry自带的,表示重试策略,参数就是重试次数,这里取的间隔数组长度+1(包括第一次失败,所以这里是4不是3)
image.png

然后我们就可以去在需要重试的地方使用RetryTemplate
image.png

最后效果
image.png

当然当然,说实话哈,Spring-Retry也算是造了一个轮子,但是其实哈仔细去查看一下Spring-Retry的实现模式,在题主的这个需求上,还是while循环然后用Sleep去停,哈哈哈哈,所以我最开始才说担心什么线程的资源占用,这都是小事,毕竟定时器或者什么定时任务这玩意儿,底层不都还是while循环嘛,所以我觉得我都可以给你整一个简要版,弄一个CustomRetryTemplate

image.png

然后调用的话也很简单
image.png

最终效果也是一样的
image.png

所有代码我都放在了github上,稍微有点多,就不在这里发了,可以自取哈

就酱,( ^_^ )/~~拜拜

最后再提一嘴,真要使用Spring-Retry,记得把spring-aspects的配置要加上哈,我的pom里是有的
image.png

沫尐诺 2022-09-19 22:15:44

消息队列不太好实现这种逻辑,一般都是用来解耦两个系统的。

用redis实现更简单点,可以使用redis的set或list数据结构。比如对应1分钟后,10分钟后,一小时后创建三个list。

用一个job轮训重试,成功了就删除,失败了就放到下一个list中。

痴意少年 2022-09-19 22:15:44

可以用消息队列中间件比如rabbitmq,也可以用redis,看自己的需求使用消息队列各方面的可靠性要好些,看自己选择。rabbitmq有一个插件 rabbitmq_delayed_message_exchange 是专门来干这种事情的。

就是爱搞怪 2022-09-19 22:15:44

1.使用for循环,通过try catch , 但是这样会一直占用一个线程的资源.
你的意思是对每一个请求进行for循环?出现异常就保留这个线程?那这样的确是不合理的。

思路肯定还是要用到生产者-消费者模型。 出现异常时写入生产队列。至于实现,消息中间件当然最好,不过不想额外部署的话,关系型数据库或者JAVA内置的队列啥的都可以。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文