use of reactor.retry.Repeat in project spring-cloud-gateway by spring-cloud.
the class RetryGatewayFilterFactory method apply.
@Override
public GatewayFilter apply(RetryConfig retryConfig) {
retryConfig.validate();
Repeat<ServerWebExchange> statusCodeRepeat = null;
if (!retryConfig.getStatuses().isEmpty() || !retryConfig.getSeries().isEmpty()) {
Predicate<RepeatContext<ServerWebExchange>> repeatPredicate = context -> {
ServerWebExchange exchange = context.applicationContext();
if (exceedsMaxIterations(exchange, retryConfig)) {
return false;
}
HttpStatusCode statusCode = exchange.getResponse().getStatusCode();
boolean retryableStatusCode = retryConfig.getStatuses().contains(statusCode);
// null status code might mean a network exception?
if (!retryableStatusCode && statusCode != null) {
// try the series
retryableStatusCode = false;
for (int i = 0; i < retryConfig.getSeries().size(); i++) {
if (statusCode instanceof HttpStatus) {
HttpStatus httpStatus = (HttpStatus) statusCode;
if (httpStatus.series().equals(retryConfig.getSeries().get(i))) {
retryableStatusCode = true;
break;
}
}
}
}
final boolean finalRetryableStatusCode = retryableStatusCode;
trace("retryableStatusCode: %b, statusCode %s, configured statuses %s, configured series %s", () -> finalRetryableStatusCode, () -> statusCode, retryConfig::getStatuses, retryConfig::getSeries);
HttpMethod httpMethod = exchange.getRequest().getMethod();
boolean retryableMethod = retryConfig.getMethods().contains(httpMethod);
trace("retryableMethod: %b, httpMethod %s, configured methods %s", () -> retryableMethod, () -> httpMethod, retryConfig::getMethods);
return retryableMethod && finalRetryableStatusCode;
};
statusCodeRepeat = Repeat.onlyIf(repeatPredicate).doOnRepeat(context -> reset(context.applicationContext()));
BackoffConfig backoff = retryConfig.getBackoff();
if (backoff != null) {
statusCodeRepeat = statusCodeRepeat.backoff(getBackoff(backoff));
}
}
// TODO: support timeout, backoff, jitter, etc... in Builder
Retry<ServerWebExchange> exceptionRetry = null;
if (!retryConfig.getExceptions().isEmpty()) {
Predicate<RetryContext<ServerWebExchange>> retryContextPredicate = context -> {
ServerWebExchange exchange = context.applicationContext();
if (exceedsMaxIterations(exchange, retryConfig)) {
return false;
}
Throwable exception = context.exception();
for (Class<? extends Throwable> retryableClass : retryConfig.getExceptions()) {
if (retryableClass.isInstance(exception) || (exception != null && retryableClass.isInstance(exception.getCause()))) {
trace("exception or its cause is retryable %s, configured exceptions %s", () -> getExceptionNameWithCause(exception), retryConfig::getExceptions);
HttpMethod httpMethod = exchange.getRequest().getMethod();
boolean retryableMethod = retryConfig.getMethods().contains(httpMethod);
trace("retryableMethod: %b, httpMethod %s, configured methods %s", () -> retryableMethod, () -> httpMethod, retryConfig::getMethods);
return retryableMethod;
}
}
trace("exception or its cause is not retryable %s, configured exceptions %s", () -> getExceptionNameWithCause(exception), retryConfig::getExceptions);
return false;
};
exceptionRetry = Retry.onlyIf(retryContextPredicate).doOnRetry(context -> reset(context.applicationContext())).retryMax(retryConfig.getRetries());
BackoffConfig backoff = retryConfig.getBackoff();
if (backoff != null) {
exceptionRetry = exceptionRetry.backoff(getBackoff(backoff));
}
}
GatewayFilter gatewayFilter = apply(retryConfig.getRouteId(), statusCodeRepeat, exceptionRetry);
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return gatewayFilter.filter(exchange, chain);
}
@Override
public String toString() {
return filterToStringCreator(RetryGatewayFilterFactory.this).append("routeId", retryConfig.getRouteId()).append("retries", retryConfig.getRetries()).append("series", retryConfig.getSeries()).append("statuses", retryConfig.getStatuses()).append("methods", retryConfig.getMethods()).append("exceptions", retryConfig.getExceptions()).toString();
}
};
}
Aggregations