博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
聊聊spring cloud gateway的RetryGatewayFilter
阅读量:6487 次
发布时间:2019-06-23

本文共 5738 字,大约阅读时间需要 19 分钟。

  hot3.png

本文主要研究一下spring cloud gateway的RetryGatewayFilter

GatewayAutoConfiguration

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java

@Configuration@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)@EnableConfigurationProperties@AutoConfigureBefore(HttpHandlerAutoConfiguration.class)@AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})@ConditionalOnClass(DispatcherHandler.class)public class GatewayAutoConfiguration {    //......	@Bean	public RetryGatewayFilterFactory retryGatewayFilterFactory() {		return new RetryGatewayFilterFactory();	}    //......}

默认启用了RetryGatewayFilterFactory

RetryGatewayFilterFactory

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java

public class RetryGatewayFilterFactory extends AbstractGatewayFilterFactory
{ private static final Log log = LogFactory.getLog(RetryGatewayFilterFactory.class); public RetryGatewayFilterFactory() { super(RetryConfig.class); } @Override public GatewayFilter apply(RetryConfig retryConfig) { retryConfig.validate(); Predicate
> predicate = context -> { ServerWebExchange exchange = context.applicationContext(); if (exceedsMaxIterations(exchange, retryConfig)) { return false; } HttpStatus statusCode = exchange.getResponse().getStatusCode(); HttpMethod httpMethod = exchange.getRequest().getMethod(); boolean retryableStatusCode = retryConfig.getStatuses().contains(statusCode); if (!retryableStatusCode && statusCode != null) { // null status code might mean a network exception? // try the series retryableStatusCode = retryConfig.getSeries().stream() .anyMatch(series -> statusCode.series().equals(series)); } boolean retryableMethod = retryConfig.getMethods().contains(httpMethod); return retryableMethod && retryableStatusCode; }; Repeat
repeat = Repeat.onlyIf(predicate) .doOnRepeat(context -> reset(context.applicationContext())); //TODO: support timeout, backoff, jitter, etc... in Builder Predicate
> retryContextPredicate = context -> { if (exceedsMaxIterations(context.applicationContext(), retryConfig)) { return false; } for (Class
clazz : retryConfig.getExceptions()) { if (clazz.isInstance(context.exception())) { return true; } } return false; }; Retry
reactorRetry = Retry.onlyIf(retryContextPredicate) .doOnRetry(context -> reset(context.applicationContext())) .retryMax(retryConfig.getRetries()); return apply(repeat, reactorRetry); } public boolean exceedsMaxIterations(ServerWebExchange exchange, RetryConfig retryConfig) { Integer iteration = exchange.getAttribute("retry_iteration"); //TODO: deal with null iteration return iteration != null && iteration >= retryConfig.getRetries(); } public void reset(ServerWebExchange exchange) { //TODO: what else to do to reset SWE? exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_ALREADY_ROUTED_ATTR); } @Deprecated public GatewayFilter apply(Repeat
repeat) { return apply(repeat, Retry.onlyIf(ctxt -> false)); } public GatewayFilter apply(Repeat
repeat, Retry
retry) { return (exchange, chain) -> { log.trace("Entering retry-filter"); int iteration = exchange.getAttributeOrDefault("retry_iteration", -1); exchange.getAttributes().put("retry_iteration", iteration + 1); return Mono.fromDirect(chain.filter(exchange) .log("retry-filter", Level.INFO) .retryWhen(retry.withApplicationContext(exchange)) .repeatWhen(repeat.withApplicationContext(exchange))); }; } //......}
  • 可以看到这个filter使用了reactor的Retry组件,同时往exchange的attribues添加retry_iteration,用来记录重试次数,该值默认从-1开始,第一次执行的时候,retry_iteration+1为0。之后每重试一次,就添加1。
  • filter的apply接收两个参数,一个是Repeat<ServerWebExchange>,一个是Retry<ServerWebExchange>。
  • repeat与retry的区别是repeat是在onCompleted的时候会重试,而retry是在onError的时候会重试。这里由于不一定是异常的时候才可能重试,所以加了repeat。

RetryConfig

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java

public static class RetryConfig {		private int retries = 3;				private List
series = toList(Series.SERVER_ERROR); private List
statuses = new ArrayList<>(); private List
methods = toList(HttpMethod.GET); private List
> exceptions = toList(IOException.class); //...... public void validate() { Assert.isTrue(this.retries > 0, "retries must be greater than 0"); Assert.isTrue(!this.series.isEmpty() || !this.statuses.isEmpty(), "series and status may not both be empty"); Assert.notEmpty(this.methods, "methods may not be empty"); } //...... }

可以看到配置文件有5个属性,如下:

  • retries,默认为3,用来标识重试次数
  • series,用来指定哪些段的状态码需要重试,默认SERVER_ERROR即5xx
  • statuses,用于指定哪些状态需要重试,默认为空,它跟series至少得指定一个
  • methods,用于指定那些方法的请求需要重试,默认为GET
  • exceptions,用于指定哪些异常需要重试,默认为java.io.IOException

实例

spring:  cloud:    gateway:      routes:      - id: retry-demo        uri: http://localhost:9090        predicates:        - Path=/retry/**        filters:        - name: Retry          args:           retries: 15           series:            - SERVER_ERROR            - CLIENT_ERROR           methods:            - GET            - POST           exceptions:            - java.io.IOException            - java.util.concurrent.TimeoutException

这里指定了针对4xx及5xx的GET或POST方法或者IOException或TimeoutException的时候进行重试,重试次数为15次。

小结

RetryGatewayFilter借助了reactor-addons的retry组件进行了重试,主要使用了Mono的repeatWhen及retryWhen方法,前者在onCompleted的时候触发,后者在onError的时候触发。

doc

转载于:https://my.oschina.net/go4it/blog/1832477

你可能感兴趣的文章
HTML5前端教程分享:CSS浏览器常见兼容问题
查看>>
Material Design之AppBarLayout
查看>>
一服多开
查看>>
从CVS迁移到SVN
查看>>
总部与前线
查看>>
微软推出Windows 10专业教育版:Cortana没了
查看>>
TensorFlow教程之API DOC 6.1.2Class tensorflow::EnvWrapper
查看>>
多目标跟踪突破:上交大&中兴 MOT Challenge 测评获第一
查看>>
控制ASP.NET Web API 调用频率
查看>>
系统诊断小技巧(7):利用Iptables进行排查和诊断的简易方案
查看>>
IPv6的渗透率比人们想象的要快速?
查看>>
针对Windows零日漏洞,微软是不是太过“无作为”了?
查看>>
推特解散商业团队 终止开发“Buy”按钮
查看>>
英特尔SSD:17年将专注于3D NAND和PCIe
查看>>
python (3):wxPython打包app,报错
查看>>
给网站更换服务器需要注意什么?
查看>>
成长型企业ERP系统实施的八大准则
查看>>
nginx重启脚本
查看>>
理解Linux系统/etc/init.d目录和/etc/rc.local脚本
查看>>
代码整洁之道
查看>>