试试ribbon.retryableStatusCodes=404,502,504
更新:
首先在我看来,ConnectException 应该与代码 502 相关联,而 504 是 SocketTimeoutException。如有错误请指正。
抱歉,云网关没有深入研究,但是它的LB可以选择使用Ribbon。
假设您使用 Ribbon 和 OKHttp via ribbon.OkHttp.enabled。
OkHttpRibbonConfiguration 将初始化一个 OkHttpLoadBalancingClient bean,它执行请求。在其execute() 中,它在每次请求执行期间首先创建一个RetryCallback 匿名实现对象。 RetryCallback负责执行请求和重试执行。
我们来看看RetryCallback的逻辑。收到响应后,它会检查响应状态码是否可重试。如果类加载器中存在RetryTemplate类,则loadBalancedRetryPolicyFactory的实现为RibbonLoadBalancedRetryPolicyFactory。它用于创建RibbonLoadBalancedRetryPolicy 对象(以下retryPlicy)。
executeWithRetry() 用RetryPolicy 创建一个RetryTemplate。 (前提条件,通过将请求设置为可重试,在spring cloud gateway中启用重试)。
public OkHttpRibbonResponse execute(...) throws Exception {
final LoadBalancedRetryPolicy retryPolicy = loadBalancedRetryPolicyFactory.create(this.getClientName(), this);
...
final Request request = newRequest.toRequest();
Response response = httpClient.newCall(request).execute();
if(retryPolicy.retryableStatusCode(response.code())) {
ResponseBody responseBody = response.peekBody(Integer.MAX_VALUE);
response.close();
throw new OkHttpStatusCodeException(RetryableOkHttpLoadBalancingClient.this.clientName,
response, responseBody, newRequest.getURI());
}
return new OkHttpRibbonResponse(response, newRequest.getUri());
}
private OkHttpRibbonResponse executeWithRetry(...) throws Exception {
RetryTemplate retryTemplate = new RetryTemplate();
BackOffPolicy backOffPolicy = loadBalancedBackOffPolicyFactory.createBackOffPolicy(this.getClientName());
retryTemplate.setBackOffPolicy(backOffPolicy == null ? new NoBackOffPolicy() : backOffPolicy);
RetryListener[] retryListeners = this.loadBalancedRetryListenerFactory.createRetryListeners(this.getClientName());
if (retryListeners != null && retryListeners.length != 0) {
retryTemplate.setListeners(retryListeners);
}
boolean retryable = isRequestRetryable(request); //HERE
retryTemplate.setRetryPolicy(retryPolicy == null || !retryable ? new NeverRetryPolicy()
: new RetryPolicy(request, retryPolicy, this, this.getClientName()));
return retryTemplate.execute(callback, recoveryCallback);
}
private boolean isRequestRetryable(ContextAwareRequest request) {
return request.getContext() == null ? true :
BooleanUtils.toBooleanDefaultIfNull(request.getContext().getRetryable(), true);
}
在retryableStatusCode()中,检查retryableStatusCodes是否包含响应状态码。
public class RibbonLoadBalancedRetryPolicy implements LoadBalancedRetryPolicy {
public static final IClientConfigKey<String> RETRYABLE_STATUS_CODES = new CommonClientConfigKey<String>("retryableStatusCodes") {};
....
List<Integer> retryableStatusCodes = new ArrayList<>();
public RibbonLoadBalancedRetryPolicy(String serviceId, RibbonLoadBalancerContext context, ServiceInstanceChooser loadBalanceChooser,
IClientConfig clientConfig) {
this.serviceId = serviceId;
this.lbContext = context;
this.loadBalanceChooser = loadBalanceChooser;
String retryableStatusCodesProp = clientConfig.getPropertyAsString(RETRYABLE_STATUS_CODES, "");
String[] retryableStatusCodesArray = retryableStatusCodesProp.split(",");
for(String code : retryableStatusCodesArray) {
if(!StringUtils.isEmpty(code)) {
try {
retryableStatusCodes.add(Integer.valueOf(code.trim()));
} catch (NumberFormatException e) {
//TODO log
}
}
}
}
...
@Override
public boolean retryableStatusCode(int statusCode) {
return retryableStatusCodes.contains(statusCode);
}
}
如果包含,则抛出扩展RetryableStatusCodeException 的OkHttpStatusCodeException。并且RibbonRecoveryCallback 捕捉到这个异常,检查异常是否是RetryableStatusCodeException 的实现。如果是,则RetryTemplate 继续重试。或者,抛出不可重试的 Expcetion 来中断重试。