如何实现Feign超过重试次数后的告警操作

如何实现Feign超过重试次数后的告警操作今天同事问我,使用Feign进行Http请求,当出现网络问题进行重试,假如超过了重试次数后想要发起一个告警要怎么做?

大家好,欢迎来到IT知识分享网。

哈喽,大家好,我是强哥。

今天同事问我,使用Feign进行Http请求,当出现网络问题进行重试,假如超过了重试次数后想要发起一个告警要怎么做?

强哥被问到的时候,也突然懵了一下,之前使用Feign配置Retryer的时候,都是使用Feign的默认实现Retryer.Default,配置好重试次数和时间之后,就不管了。也没遇到要处理超过重试次数如何发起告警的问题。

那么,针对这个问题我们要怎么解决呢?

简单的在网上找了下,呵呵,全是关于怎么配置重试次数的,重试失败后的额外操作一个也没有多说。

没法,看着同事含情脉脉的眼神,不给她解决下有点不好意思。那要怎么搞的?看源码呗。

Feign触发请求调用的核心代码在SynchronousMethodHandler下的invoke方法:

 @Override public Object invoke(Object[] argv) throws Throwable { RequestTemplate template = buildTemplateFromArgs.create(argv); Retryer retryer = this.retryer.clone(); while (true) { try { return executeAndDecode(template); } catch (RetryableException e) { retryer.continueOrPropagate(e); if (logLevel != Logger.Level.NONE) { logger.logRetry(metadata.configKey(), logLevel); } continue; } } } 

这里我们可以看到,executeAndDecode方法是核心,进去看看(代码有点长,强哥这里就挑有用的展示):

 Object executeAndDecode(RequestTemplate template) throws Throwable { //根据Feign配置的请求拦截器进行请求构建 Request request = targetRequest(template); Response response; try { //发送请求获取结果 response = client.execute(request, options); } catch (IOException e) { //网络异常走这里 if (logLevel != Logger.Level.NONE) { logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start)); } //执行Retryer throw errorExecuting(request, e); } boolean shouldClose = true; try { //省略部分代码 …… //调用接口后返回结果 if (response.status() >= 200 && response.status() < 300) { if (void.class == metadata.returnType()) { return null; } else { return decode(response); } } else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) { return decode(response); } else { throw errorDecoder.decode(metadata.configKey(), response); } } catch (IOException e) { if (logLevel != Logger.Level.NONE) { logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime); } throw errorReading(request, response, e); } finally { if (shouldClose) { ensureClosed(response.body()); } } } 

先讲讲上面代码的执行流程:

  • 拼接Request
  • 发起请求,获取结果
  • 异常判断:1、如果是网络问题,则进入重试;2、如果发起请求后有获取到响应码,则根据响应码进行对应的处理。

那么,Feign什么时候请求失败会走Retryer呢?没错,就是throw errorExecuting(request, e);这句代码:

static FeignException errorExecuting(Request request, IOException cause) { return new RetryableException( format("%s executing %s %s", cause.getMessage(), request.method(), request.url()), cause, null); } 

在抛出RetryableException异常后,有细看代码的小伙伴应该发现了,这个异常会被最开头的invoke方法捕获,然后通过retryer.continueOrPropagate(e);进入Retryer的continueOrPropagate方法。

那么重点就在continueOrPropagate方法里了(这里直接给出Retryer.Default的实现代码)。

 public void continueOrPropagate(RetryableException e) { if (attempt++ >= maxAttempts) { throw e; } long interval; if (e.retryAfter() != null) { interval = e.retryAfter().getTime() - currentTimeMillis(); if (interval > maxPeriod) { interval = maxPeriod; } if (interval < 0) { return; } } else { interval = nextMaxInterval(); } try { Thread.sleep(interval); } catch (InterruptedException ignored) { Thread.currentThread().interrupt(); } sleptForMillis += interval; } 

代码逻辑很简单,就是判断当前重试次数是否大于最大重试次数,不是就等待一会然后再到最开始贴出的invoke方法的循环里再次发起请求(invoke方法里有一个while(true)的循环来重复发起请求);如果超过了重试次数,就直接抛异常了:

if (attempt++ >= maxAttempts) { throw e; } 

哈哈,那么重点也就是这个超过重试次数,要抛出异常的地方了。从上面的代码可以看出,抛出的是RetryableException类型的异常。

也就意味着,如果Feign在发起请求后,重试次数达到了最大重试次数还是失败的话,就会抛出RetryableException异常。

这里强哥重点强调是为了让小伙伴们明白:我们其实只要在自己的业务代码使用Feign发起请求的地方,前后添加上try catch相关的代码捕获这个异常就可以了。

给出一个强哥的解决方式:

try { //发起Feign请求 Object feignResult = feignService.getUserId(json); }catch (HystrixRuntimeException e) { if (e.getCause() instanceof RetryableException) { //告警代码 weChatNoticeUtil.sendWxNoticeMsg("请求重试出错啦,看看是不是服务再重启或者断网咯"); }else { log.warn("正常访问出错,看看是不是服务地址变更啦", e); } } 

捕获异常后在catch中进行对应的告警操作就可以啦。

这里catch捕获的是HystrixRuntimeException类型的异常,且在catch的处理代码中,又对请求异常的类型进行了判断,这是为什么呢?

对请求类型的判断是因为:前面有说过,并不是所有的请求都会走Retryer发起重试,如果请求能正常发起,并获取到返回码不管成功失败都是不会走Retryer的,比如请求404错误的话就不会走重试机制。

一般都是网络有问题才会走Retryer。而从上面源码的分析我们可以看出Retryer的报错类型是RetryableException,所以专门针对它进行了特殊处理。

至于catch捕获的是HystrixRuntimeException类型,其实是框架对应实现抛出来的,具体怎么知道是HystrixRuntimeException。其实只要先进行try catch(Exception e)来捕获异常,在异常捕获得地方打上断点就能知道具体是什么类型的异常啦:

如何实现Feign超过重试次数后的告警操作

好啦,所以整个问题,其实用一个try catch就解决啦。

OK,今天就水到这里。对于我们遇到的陌生的问题,其实,如果网上找不到答案,最快的办法就是自己打断点走源码来获取解决办法啦。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/59332.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信