From 5bfd4610de45bb9ca4740d9db93bfc96338b6a2f Mon Sep 17 00:00:00 2001 From: Olga Maciaszek-Sharma Date: Thu, 11 Feb 2021 12:11:52 +0100 Subject: [PATCH 1/4] Backport retryable lb exchange filter function (#902) --- README.adoc | 2 +- docs/src/main/asciidoc/_configprops.adoc | 4 + .../main/asciidoc/spring-cloud-commons.adoc | 77 +++++-- .../LoadBalancerRetryProperties.java | 72 ++++++ .../loadbalancer/RetryableRequestContext.java | 79 +++++++ .../reactive/ExchangeFilterFunctionUtils.java | 44 ++++ .../reactive/LoadBalancerRetryContext.java | 83 +++++++ .../reactive/LoadBalancerRetryPolicy.java | 58 +++++ ...torLoadBalancerExchangeFilterFunction.java | 10 +- ...FilterFunctionLoadBalancerRetryPolicy.java | 60 +++++ ...bleLoadBalancerExchangeFilterFunction.java | 218 ++++++++++++++++++ .../RetryableStatusCodeException.java | 28 +++ ...xchangeFilterFunctionIntegrationTests.java | 218 ++++++++++++++++++ ...adBalancerExchangeFilterFunctionTests.java | 161 +++++++++++++ 14 files changed, 1086 insertions(+), 28 deletions(-) create mode 100644 spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/RetryableRequestContext.java create mode 100644 spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/ExchangeFilterFunctionUtils.java create mode 100644 spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerRetryContext.java create mode 100644 spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerRetryPolicy.java create mode 100644 spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableExchangeFilterFunctionLoadBalancerRetryPolicy.java create mode 100644 spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableLoadBalancerExchangeFilterFunction.java create mode 100644 spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableStatusCodeException.java create mode 100644 spring-cloud-commons/src/test/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableLoadBalancerExchangeFilterFunctionIntegrationTests.java create mode 100644 spring-cloud-commons/src/test/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableLoadBalancerExchangeFilterFunctionTests.java diff --git a/README.adoc b/README.adoc index 6aeed1c4..8fdcaee7 100644 --- a/README.adoc +++ b/README.adoc @@ -27,7 +27,7 @@ Extract the files into the JDK/jre/lib/security folder for whichever version of == Building -:jdkversion: 1.7 +:jdkversion: 1.8 === Basic Compile and Test diff --git a/docs/src/main/asciidoc/_configprops.adoc b/docs/src/main/asciidoc/_configprops.adoc index 0f7126ae..dd749d13 100644 --- a/docs/src/main/asciidoc/_configprops.adoc +++ b/docs/src/main/asciidoc/_configprops.adoc @@ -33,6 +33,10 @@ |spring.cloud.loadbalancer.health-check.refetch-instances | false | Indicates whether the instances should be refetched by the HealthCheckServiceInstanceListSupplier. This can be used if the instances can be updated and the underlying delegate does not provide an ongoing flux. |spring.cloud.loadbalancer.health-check.refetch-instances-interval | 25s | Interval for refetching available service instances. |spring.cloud.loadbalancer.health-check.repeat-health-check | true | Indicates whether health checks should keep repeating. It might be useful to set it to false if periodically refetching the instances, as every refetch will also trigger a healthcheck. +|spring.cloud.loadbalancer.retry.backoff.enabled | false | Indicates whether Reactor Retry backoffs should be applied. +|spring.cloud.loadbalancer.retry.backoff.jitter | 0.5 | Used to set {@link RetryBackoffSpec#jitter}. +|spring.cloud.loadbalancer.retry.backoff.max-backoff | | Used to set {@link RetryBackoffSpec#maxBackoff}. +|spring.cloud.loadbalancer.retry.backoff.min-backoff | 5ms | Used to set {@link RetryBackoffSpec#minBackoff}. |spring.cloud.loadbalancer.retry.enabled | true | |spring.cloud.loadbalancer.retry.max-retries-on-next-service-instance | 1 | Number of retries to be executed on the next ServiceInstance. A ServiceInstance is chosen before each retry call. |spring.cloud.loadbalancer.retry.max-retries-on-same-service-instance | 0 | Number of retries to be executed on the same ServiceInstance. diff --git a/docs/src/main/asciidoc/spring-cloud-commons.adoc b/docs/src/main/asciidoc/spring-cloud-commons.adoc index ceba4ef7..39a135a4 100644 --- a/docs/src/main/asciidoc/spring-cloud-commons.adoc +++ b/docs/src/main/asciidoc/spring-cloud-commons.adoc @@ -452,11 +452,67 @@ set the `spring.cloud.loadbalancer.ribbon.enabled` property to `false`. A load-balanced `RestTemplate` can be configured to retry failed requests. By default, this logic is disabled. -You can enable it by adding link:https://github.com/spring-projects/spring-retry[Spring Retry] to your application's classpath. +For the non-reactive version (with `RestTemplate`), you can enable it by adding link:https://github.com/spring-projects/spring-retry[Spring Retry] to your application's classpath. + +To use the reactive version of load-balanced retries in the Hoxton release train, you will need to instantiate your own `RetryableLoadBalancerExchangeFilterFunction` bean: + +[source,java,indent=0] +---- +@Configuration +public class MyConfiguration { + + @Bean + RetryableLoadBalancerExchangeFilterFunction retryableLoadBalancerExchangeFilterFunction( + LoadBalancerRetryProperties properties, + ReactiveLoadBalancer.Factory factory) { + return new RetryableLoadBalancerExchangeFilterFunction( + new RetryableExchangeFilterFunctionLoadBalancerRetryPolicy( + properties), + factory, properties); + } +} +---- + +Then you can use it as a filter while building `webClient` instances: + +[source,java,indent=0] +---- +public class MyClass { + @Autowired + private RetryableLoadBalancerExchangeFilterFunction retryableLbFunction; + + public Mono doOtherStuff() { + return WebClient.builder().baseUrl("http://stores") + .filter(retryableLbFunction) + .build() + .get() + .uri("/stores") + .retrieve() + .bodyToMono(String.class); + } +} +---- If you would like to disable the retry logic with Spring Retry on the classpath, you can set `spring.cloud.loadbalancer.retry.enabled=false`. -If you would like to implement a `BackOffPolicy` in your retries, you need to create a bean of type `LoadBalancedRetryFactory` and override the `createBackOffPolicy()` method. +For the non-reactive implementation, if you would like to implement a `BackOffPolicy` in your retries, you need to create a bean of type `LoadBalancedRetryFactory` and override the `createBackOffPolicy()` method. + +For the reactive implementation, you just need to enable it by setting `spring.cloud.loadbalancer.retry.backoff.enabled` to `false`. + +You can set: + +- `spring.cloud.loadbalancer.retry.maxRetriesOnSameServiceInstance` - indicates how many times a request should be retried on the same `ServiceInstance` (counted separately for every selected instance) +- `spring.cloud.loadbalancer.retry.maxRetriesOnNextServiceInstance` - indicates how many times a request should be retried a newly selected `ServiceInstance` +- `spring.cloud.loadbalancer.retry.retryableStatusCodes` - the status codes on which to always retry a failed request. + +For the reactive implementation, you can additionally set: +- `spring.cloud.loadbalancer.retry.backoff.minBackoff` - Sets the minimum backoff duration (by default, 5 milliseconds) +- `spring.cloud.loadbalancer.retry.backoff.maxBackoff` - Sets the maximum backoff duration (by default, max long value of milliseconds) +- `spring.cloud.loadbalancer.retry.backoff.jitter` - Sets the jitter used for calculationg the actual backoff duration for each call (by default, 0.5). + +For the reactive implementation, you can also implement your own `LoadBalancerRetryPolicy` to have more detailed control over the load-balanced call retries. + +WARN:: For the non-reactive version, if you chose to override the `LoadBalancedRetryFactory` while using the Spring Cloud LoadBalancer-backed approach, make sure you annotate your bean with `@Order` and set it to a higher precedence than `1000`, which is the order set on the `BlockingLoadBalancedRetryFactory`. ===== Ribbon-based retries @@ -475,23 +531,6 @@ For the Spring Cloud LoadBalancer-backed implementation, you can set: WARN:: If you chose to override the `LoadBalancedRetryFactory` while using the Spring Cloud LoadBalancer-backed approach, make sure you annotate your bean with `@Order` and set it to a higher precedence than `1000`, which is the order set on the `BlockingLoadBalancedRetryFactory`. -==== -[source,java,indent=0] ----- -@Configuration -public class MyConfiguration { - @Bean - LoadBalancedRetryFactory retryFactory() { - return new LoadBalancedRetryFactory() { - @Override - public BackOffPolicy createBackOffPolicy(String service) { - return new ExponentialBackOffPolicy(); - } - }; - } -} ----- -==== NOTE: `client` in the preceding examples should be replaced with your Ribbon client's name. diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerRetryProperties.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerRetryProperties.java index fbded2dd..58156e6b 100644 --- a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerRetryProperties.java +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerRetryProperties.java @@ -16,9 +16,12 @@ package org.springframework.cloud.client.loadbalancer; +import java.time.Duration; import java.util.HashSet; import java.util.Set; +import reactor.util.retry.RetryBackoffSpec; + import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.http.HttpMethod; @@ -54,6 +57,11 @@ public class LoadBalancerRetryProperties { */ private Set retryableStatusCodes = new HashSet<>(); + /** + * Properties for Reactor Retry backoffs in Spring Cloud LoadBalancer. + */ + private Backoff backoff = new Backoff(); + /** * Returns true if the load balancer should retry failed requests. * @return True if the load balancer should retry failed requests; false otherwise. @@ -102,4 +110,68 @@ public class LoadBalancerRetryProperties { this.retryableStatusCodes = retryableStatusCodes; } + public Backoff getBackoff() { + return backoff; + } + + public void setBackoff(Backoff backoff) { + this.backoff = backoff; + } + + public static class Backoff { + + /** + * Indicates whether Reactor Retry backoffs should be applied. + */ + private boolean enabled = false; + + /** + * Used to set {@link RetryBackoffSpec#minBackoff}. + */ + private Duration minBackoff = Duration.ofMillis(5); + + /** + * Used to set {@link RetryBackoffSpec#maxBackoff}. + */ + private Duration maxBackoff = Duration.ofMillis(Long.MAX_VALUE); + + /** + * Used to set {@link RetryBackoffSpec#jitter}. + */ + private double jitter = 0.5d; + + public Duration getMinBackoff() { + return minBackoff; + } + + public void setMinBackoff(Duration minBackoff) { + this.minBackoff = minBackoff; + } + + public Duration getMaxBackoff() { + return maxBackoff; + } + + public void setMaxBackoff(Duration maxBackoff) { + this.maxBackoff = maxBackoff; + } + + public double getJitter() { + return jitter; + } + + public void setJitter(double jitter) { + this.jitter = jitter; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + } + } diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/RetryableRequestContext.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/RetryableRequestContext.java new file mode 100644 index 00000000..b49a2093 --- /dev/null +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/RetryableRequestContext.java @@ -0,0 +1,79 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.client.loadbalancer; + +import java.util.Objects; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.core.style.ToStringCreator; + +/** + * A request context object that allows storing information on previously used service + * instances. + * + * @author Olga Maciaszek-Sharma + * @since 2.2.7 + */ +public class RetryableRequestContext extends DefaultRequestContext { + + private ServiceInstance previousServiceInstance; + + public RetryableRequestContext(ServiceInstance previousServiceInstance) { + this.previousServiceInstance = previousServiceInstance; + } + + public RetryableRequestContext(ServiceInstance previousServiceInstance, String hint) { + super(hint); + this.previousServiceInstance = previousServiceInstance; + } + + public ServiceInstance getPreviousServiceInstance() { + return previousServiceInstance; + } + + public void setPreviousServiceInstance(ServiceInstance previousServiceInstance) { + this.previousServiceInstance = previousServiceInstance; + } + + @Override + public String toString() { + ToStringCreator to = new ToStringCreator(this); + to.append("previousServiceInstance", previousServiceInstance); + return to.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof RetryableRequestContext)) { + return false; + } + if (!super.equals(o)) { + return false; + } + RetryableRequestContext context = (RetryableRequestContext) o; + return Objects.equals(previousServiceInstance, context.previousServiceInstance); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), previousServiceInstance); + } + +} diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/ExchangeFilterFunctionUtils.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/ExchangeFilterFunctionUtils.java new file mode 100644 index 00000000..8e4ce151 --- /dev/null +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/ExchangeFilterFunctionUtils.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.client.loadbalancer.reactive; + +import java.net.URI; + +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; + +/** + * A utility class for load-balanced {@link ExchangeFilterFunction} instances. + * + * @author Olga Maciaszek-Sharma + * @since 2.2.7 + */ +public final class ExchangeFilterFunctionUtils { + + private ExchangeFilterFunctionUtils() { + throw new IllegalStateException("Can't instantiate a utility class."); + } + + static ClientRequest buildClientRequest(ClientRequest request, URI uri) { + return ClientRequest.create(request.method(), uri) + .headers(headers -> headers.addAll(request.headers())) + .cookies(cookies -> cookies.addAll(request.cookies())) + .attributes(attributes -> attributes.putAll(request.attributes())) + .body(request.body()).build(); + } + +} diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerRetryContext.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerRetryContext.java new file mode 100644 index 00000000..60721560 --- /dev/null +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerRetryContext.java @@ -0,0 +1,83 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.client.loadbalancer.reactive; + +import org.springframework.http.HttpMethod; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; + +/** + * Stores the data for a load-balanced call that is being retried. + * + * @author Olga Maciaszek-Sharma + * @since 2.2.7 + */ +class LoadBalancerRetryContext { + + private final ClientRequest request; + + private ClientResponse clientResponse; + + private Integer retriesSameServiceInstance = 0; + + private Integer retriesNextServiceInstance = 0; + + LoadBalancerRetryContext(ClientRequest request) { + this.request = request; + } + + ClientRequest getRequest() { + return request; + } + + ClientResponse getClientResponse() { + return clientResponse; + } + + void setClientResponse(ClientResponse clientResponse) { + this.clientResponse = clientResponse; + } + + Integer getRetriesSameServiceInstance() { + return retriesSameServiceInstance; + } + + void incrementRetriesSameServiceInstance() { + retriesSameServiceInstance++; + } + + void resetRetriesSameServiceInstance() { + retriesSameServiceInstance = 0; + } + + Integer getRetriesNextServiceInstance() { + return retriesNextServiceInstance; + } + + void incrementRetriesNextServiceInstance() { + retriesNextServiceInstance++; + } + + Integer getResponseStatusCode() { + return clientResponse.statusCode().value(); + } + + HttpMethod getRequestMethod() { + return request.method(); + } + +} diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerRetryPolicy.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerRetryPolicy.java new file mode 100644 index 00000000..35e69667 --- /dev/null +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerRetryPolicy.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.client.loadbalancer.reactive; + +import org.springframework.http.HttpMethod; + +/** + * Pluggable policy used to establish whether a given load-balanced call should be + * retried. + * + * @author Olga Maciaszek-Sharma + * @since 2.2.7 + */ +public interface LoadBalancerRetryPolicy { + + /** + * Return true to retry on the same service instance. + * @param context the context for the retry operation + * @return true to retry on the same service instance + */ + boolean canRetrySameServiceInstance(LoadBalancerRetryContext context); + + /** + * Return true to retry on the next service instance. + * @param context the context for the retry operation + * @return true to retry on the same service instance + */ + boolean canRetryNextServiceInstance(LoadBalancerRetryContext context); + + /** + * Return true to retry on the provided HTTP status code. + * @param statusCode the HTTP status code + * @return true to retry on the provided HTTP status code + */ + boolean retryableStatusCode(int statusCode); + + /** + * Return true to retry on the provided HTTP method. + * @param method the HTTP request method + * @return true to retry on the provided HTTP method + */ + boolean canRetryOnMethod(HttpMethod method); + +} diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/ReactorLoadBalancerExchangeFilterFunction.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/ReactorLoadBalancerExchangeFilterFunction.java index 537f2b8e..88fdd673 100644 --- a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/ReactorLoadBalancerExchangeFilterFunction.java +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/ReactorLoadBalancerExchangeFilterFunction.java @@ -30,6 +30,8 @@ import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.ExchangeFilterFunction; import org.springframework.web.reactive.function.client.ExchangeFunction; +import static org.springframework.cloud.client.loadbalancer.reactive.ExchangeFilterFunctionUtils.buildClientRequest; + /** * An {@link ExchangeFilterFunction} that uses {@link ReactiveLoadBalancer} to execute * requests against a correct {@link ServiceInstance}. @@ -102,12 +104,4 @@ public class ReactorLoadBalancerExchangeFilterFunction implements ExchangeFilter return "Load balancer does not contain an instance for the service " + serviceId; } - private ClientRequest buildClientRequest(ClientRequest request, URI uri) { - return ClientRequest.create(request.method(), uri) - .headers(headers -> headers.addAll(request.headers())) - .cookies(cookies -> cookies.addAll(request.cookies())) - .attributes(attributes -> attributes.putAll(request.attributes())) - .body(request.body()).build(); - } - } diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableExchangeFilterFunctionLoadBalancerRetryPolicy.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableExchangeFilterFunctionLoadBalancerRetryPolicy.java new file mode 100644 index 00000000..13f082b4 --- /dev/null +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableExchangeFilterFunctionLoadBalancerRetryPolicy.java @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.client.loadbalancer.reactive; + +import org.springframework.cloud.client.loadbalancer.LoadBalancerRetryProperties; +import org.springframework.http.HttpMethod; + +/** + * The default implementation of {@link LoadBalancerRetryPolicy}. + * + * @author Olga Maciaszek-Sharma + * @since 2.2.7 + */ +public class RetryableExchangeFilterFunctionLoadBalancerRetryPolicy + implements LoadBalancerRetryPolicy { + + private final LoadBalancerRetryProperties properties; + + public RetryableExchangeFilterFunctionLoadBalancerRetryPolicy( + LoadBalancerRetryProperties properties) { + this.properties = properties; + } + + @Override + public boolean canRetrySameServiceInstance(LoadBalancerRetryContext context) { + return context.getRetriesSameServiceInstance() < properties + .getMaxRetriesOnSameServiceInstance(); + } + + @Override + public boolean canRetryNextServiceInstance(LoadBalancerRetryContext context) { + return context.getRetriesNextServiceInstance() < properties + .getMaxRetriesOnNextServiceInstance(); + } + + @Override + public boolean retryableStatusCode(int statusCode) { + return properties.getRetryableStatusCodes().contains(statusCode); + } + + @Override + public boolean canRetryOnMethod(HttpMethod method) { + return HttpMethod.GET.equals(method) || properties.isRetryOnAllOperations(); + } + +} diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableLoadBalancerExchangeFilterFunction.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableLoadBalancerExchangeFilterFunction.java new file mode 100644 index 00000000..c213c4ed --- /dev/null +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableLoadBalancerExchangeFilterFunction.java @@ -0,0 +1,218 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.client.loadbalancer.reactive; + +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeoutException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import reactor.core.Exceptions; +import reactor.core.publisher.Mono; +import reactor.util.retry.Retry; +import reactor.util.retry.RetrySpec; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.LoadBalancerRetryProperties; +import org.springframework.cloud.client.loadbalancer.RetryableRequestContext; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.ExchangeFunction; + +import static org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools.reconstructURI; +import static org.springframework.cloud.client.loadbalancer.reactive.ExchangeFilterFunctionUtils.buildClientRequest; + +/** + * An {@link ExchangeFilterFunction} that uses {@link ReactiveLoadBalancer} to execute + * requests against a correct {@link ServiceInstance} and Reactor Retries to retry the + * call both against the same and the next service instance, based on the provided + * {@link LoadBalancerRetryPolicy}. + * + * @author Olga Maciaszek-Sharma + * @since 2.2.7 + */ +public class RetryableLoadBalancerExchangeFilterFunction + implements ExchangeFilterFunction { + + private static final Log LOG = LogFactory + .getLog(RetryableLoadBalancerExchangeFilterFunction.class); + + private static final List> exceptions = Arrays.asList( + IOException.class, TimeoutException.class, + RetryableStatusCodeException.class); + + private final LoadBalancerRetryPolicy retryPolicy; + + private final LoadBalancerRetryProperties retryProperties; + + private final ReactiveLoadBalancer.Factory loadBalancerFactory; + + public RetryableLoadBalancerExchangeFilterFunction( + LoadBalancerRetryPolicy retryPolicy, + ReactiveLoadBalancer.Factory loadBalancerFactory, + LoadBalancerRetryProperties retryProperties) { + this.retryPolicy = retryPolicy; + this.loadBalancerFactory = loadBalancerFactory; + this.retryProperties = retryProperties; + } + + public RetryableLoadBalancerExchangeFilterFunction( + ReactiveLoadBalancer.Factory loadBalancerFactory, + LoadBalancerRetryProperties retryProperties) { + this.retryPolicy = new RetryableExchangeFilterFunctionLoadBalancerRetryPolicy( + retryProperties); + this.loadBalancerFactory = loadBalancerFactory; + this.retryProperties = retryProperties; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public Mono filter(ClientRequest clientRequest, + ExchangeFunction next) { + LoadBalancerRetryContext loadBalancerRetryContext = new LoadBalancerRetryContext( + clientRequest); + Retry exchangeRetry = buildRetrySpec( + retryProperties.getMaxRetriesOnSameServiceInstance(), true); + Retry filterRetry = buildRetrySpec( + retryProperties.getMaxRetriesOnNextServiceInstance(), false); + + URI originalUrl = clientRequest.url(); + String serviceId = originalUrl.getHost(); + if (serviceId == null) { + String message = String.format( + "Request URI does not contain a valid hostname: %s", + originalUrl.toString()); + if (LOG.isWarnEnabled()) { + LOG.warn(message); + } + return Mono.just( + ClientResponse.create(HttpStatus.BAD_REQUEST).body(message).build()); + } + DefaultRequest lbRequest = new DefaultRequest<>( + new RetryableRequestContext(null)); + return Mono.defer(() -> choose(serviceId, lbRequest).flatMap(lbResponse -> { + ServiceInstance instance = lbResponse.getServer(); + lbRequest.setContext(new RetryableRequestContext(instance)); + if (instance == null) { + String message = "LoadBalancer does not contain an instance for the service " + + serviceId; + if (LOG.isWarnEnabled()) { + LOG.warn("LoadBalancer does not contain an instance for the service " + + serviceId); + } + return Mono.just(ClientResponse.create(HttpStatus.SERVICE_UNAVAILABLE) + .body(message).build()); + } + + if (LOG.isDebugEnabled()) { + LOG.debug(String.format( + "LoadBalancer has retrieved the instance for service %s: %s", + serviceId, instance.getUri())); + } + ClientRequest newRequest = buildClientRequest(clientRequest, + reconstructURI(instance, originalUrl)); + return next.exchange(newRequest).map(clientResponse -> { + loadBalancerRetryContext.setClientResponse(clientResponse); + if (shouldRetrySameServiceInstance(loadBalancerRetryContext)) { + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Retrying on status code: %d", + clientResponse.statusCode().value())); + } + throw new RetryableStatusCodeException(); + } + return clientResponse; + + }); + }).map(clientResponse -> { + loadBalancerRetryContext.setClientResponse(clientResponse); + if (shouldRetryNextServiceInstance(loadBalancerRetryContext)) { + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Retrying on status code: %d", + clientResponse.statusCode().value())); + } + throw new RetryableStatusCodeException(); + } + return clientResponse; + + }).retryWhen(exchangeRetry)).retryWhen(filterRetry); + } + + private Retry buildRetrySpec(int max, boolean transientErrors) { + LoadBalancerRetryProperties.Backoff backoffProperties = retryProperties + .getBackoff(); + if (backoffProperties.isEnabled()) { + return RetrySpec.backoff(max, backoffProperties.getMinBackoff()) + .filter(this::isRetryException) + .maxBackoff(backoffProperties.getMaxBackoff()) + .jitter(backoffProperties.getJitter()) + .transientErrors(transientErrors); + } + return RetrySpec.max(max).filter(this::isRetryException) + .transientErrors(transientErrors); + } + + private boolean shouldRetrySameServiceInstance( + LoadBalancerRetryContext loadBalancerRetryContext) { + boolean shouldRetry = retryPolicy + .retryableStatusCode(loadBalancerRetryContext.getResponseStatusCode()) + && retryPolicy + .canRetryOnMethod(loadBalancerRetryContext.getRequestMethod()) + && retryPolicy.canRetrySameServiceInstance(loadBalancerRetryContext); + if (shouldRetry) { + loadBalancerRetryContext.incrementRetriesSameServiceInstance(); + } + return shouldRetry; + } + + private boolean shouldRetryNextServiceInstance( + LoadBalancerRetryContext loadBalancerRetryContext) { + boolean shouldRetry = retryPolicy + .retryableStatusCode(loadBalancerRetryContext.getResponseStatusCode()) + && retryPolicy + .canRetryOnMethod(loadBalancerRetryContext.getRequestMethod()) + && retryPolicy.canRetryNextServiceInstance(loadBalancerRetryContext); + if (shouldRetry) { + loadBalancerRetryContext.incrementRetriesNextServiceInstance(); + loadBalancerRetryContext.resetRetriesSameServiceInstance(); + } + return shouldRetry; + } + + private boolean isRetryException(Throwable throwable) { + return exceptions.stream() + .anyMatch(exception -> exception.isInstance(throwable) + || throwable != null && exception.isInstance(throwable.getCause()) + || Exceptions.isRetryExhausted(throwable)); + } + + protected Mono> choose(String serviceId, + Request request) { + ReactiveLoadBalancer loadBalancer = loadBalancerFactory + .getInstance(serviceId); + if (loadBalancer == null) { + return Mono.just( + new org.springframework.cloud.client.loadbalancer.reactive.EmptyResponse()); + } + return Mono.from(loadBalancer.choose(request)); + } + +} diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableStatusCodeException.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableStatusCodeException.java new file mode 100644 index 00000000..b4548b8a --- /dev/null +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableStatusCodeException.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.client.loadbalancer.reactive; + +/** + * An {@link IllegalStateException} used to trigger retries based on the returned HTTP + * status code. + * + * @author Olga Maciaszek-Sharma + * @since 2.2.7 + */ +class RetryableStatusCodeException extends IllegalStateException { + +} diff --git a/spring-cloud-commons/src/test/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableLoadBalancerExchangeFilterFunctionIntegrationTests.java b/spring-cloud-commons/src/test/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableLoadBalancerExchangeFilterFunctionIntegrationTests.java new file mode 100644 index 00000000..9f57080c --- /dev/null +++ b/spring-cloud-commons/src/test/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableLoadBalancerExchangeFilterFunctionIntegrationTests.java @@ -0,0 +1,218 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.client.loadbalancer.reactive; + +import java.net.URI; +import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryProperties; +import org.springframework.cloud.client.loadbalancer.LoadBalancerRetryProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; + +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.BDDAssertions.then; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * Integration tests for {@link RetryableLoadBalancerExchangeFilterFunction}. + * + * @author Olga Maciaszek-Sharma + * @since 2.2.7 + */ +@SpringBootTest(webEnvironment = RANDOM_PORT) +class RetryableLoadBalancerExchangeFilterFunctionIntegrationTests { + + @Autowired + private RetryableLoadBalancerExchangeFilterFunction loadBalancerFunction; + + @Autowired + private SimpleDiscoveryProperties properties; + + @Autowired + private LoadBalancerRetryProperties retryProperties; + + @LocalServerPort + private int port; + + @BeforeEach + void setUp() { + DefaultServiceInstance instance = new DefaultServiceInstance(); + instance.setServiceId("testservice"); + instance.setUri(URI.create("http://localhost:" + port)); + DefaultServiceInstance instanceWithNoLifecycleProcessors = new DefaultServiceInstance(); + instanceWithNoLifecycleProcessors + .setServiceId("serviceWithNoLifecycleProcessors"); + instanceWithNoLifecycleProcessors.setUri(URI.create("http://localhost:" + port)); + properties.getInstances().put("testservice", Collections.singletonList(instance)); + properties.getInstances().put("serviceWithNoLifecycleProcessors", + Collections.singletonList(instanceWithNoLifecycleProcessors)); + } + + @Test + void correctResponseReturnedForExistingHostAndInstancePresent() { + ClientResponse clientResponse = WebClient.builder().baseUrl("http://testservice") + .filter(this.loadBalancerFunction).build().get().uri("/hello").exchange() + .block(); + + then(clientResponse.statusCode()).isEqualTo(HttpStatus.OK); + then(clientResponse.bodyToMono(String.class).block()).isEqualTo("Hello World"); + } + + @Test + void correctResponseReturnedAfterRetryingOnSameServiceInstance() { + retryProperties.setMaxRetriesOnSameServiceInstance(1); + retryProperties.getRetryableStatusCodes().add(500); + + ClientResponse clientResponse = WebClient.builder().baseUrl("http://testservice") + .filter(this.loadBalancerFunction).build().get().uri("/exception") + .exchange().block(); + + then(clientResponse.statusCode()).isEqualTo(HttpStatus.OK); + then(clientResponse.bodyToMono(String.class).block()).isEqualTo("Hello World!"); + } + + // FIXME - flaky test + @Disabled + @Test + void correctResponseReturnedAfterRetryingOnNextServiceInstanceWithBackoff() { + retryProperties.getBackoff().setEnabled(true); + retryProperties.setMaxRetriesOnSameServiceInstance(1); + DefaultServiceInstance goodRetryTestInstance = new DefaultServiceInstance(); + goodRetryTestInstance.setServiceId("retrytest"); + goodRetryTestInstance.setUri(URI.create("http://localhost:" + port)); + DefaultServiceInstance badRetryTestInstance = new DefaultServiceInstance(); + badRetryTestInstance.setServiceId("retrytest"); + badRetryTestInstance.setUri(URI.create("http://localhost:" + 8080)); + properties.getInstances().put("retrytest", + Arrays.asList(badRetryTestInstance, goodRetryTestInstance)); + retryProperties.getRetryableStatusCodes().add(500); + + ClientResponse clientResponse = WebClient.builder().baseUrl("http://retrytest") + .filter(this.loadBalancerFunction).build().get().uri("/hello").exchange() + .block(); + + then(clientResponse.statusCode()).isEqualTo(HttpStatus.OK); + then(clientResponse.bodyToMono(String.class).block()).isEqualTo("Hello World"); + + ClientResponse secondClientResponse = WebClient.builder() + .baseUrl("http://retrytest").filter(this.loadBalancerFunction).build() + .get().uri("/hello").exchange().block(); + + then(secondClientResponse.statusCode()).isEqualTo(HttpStatus.OK); + then(secondClientResponse.bodyToMono(String.class).block()) + .isEqualTo("Hello World"); + } + + @Test + void serviceUnavailableReturnedWhenNoInstancePresent() { + ClientResponse clientResponse = WebClient.builder().baseUrl("http://xxx") + .filter(this.loadBalancerFunction).build().get().exchange().block(); + + then(clientResponse.statusCode()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE); + } + + @Test + @Disabled + // FIXME 3.0.0 + void badRequestReturnedForIncorrectHost() { + ClientResponse clientResponse = WebClient.builder().baseUrl("http:///xxx") + .filter(this.loadBalancerFunction).build().get().exchange().block(); + + then(clientResponse.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + } + + @Test + void exceptionNotThrownWhenFactoryReturnsNullLifecycleProcessorsMap() { + assertThatCode(() -> WebClient.builder() + .baseUrl("http://serviceWithNoLifecycleProcessors") + .filter(this.loadBalancerFunction).build().get().uri("/hello").exchange() + .block()).doesNotThrowAnyException(); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @EnableDiscoveryClient + @EnableAutoConfiguration + @SpringBootConfiguration(proxyBeanMethods = false) + @RestController + static class Config { + + AtomicInteger exceptionCallsCount = new AtomicInteger(); + + @GetMapping("/hello") + public String hello() { + return "Hello World"; + } + + @GetMapping("/callback") + String callbackTestResult() { + return "callbackTestResult"; + } + + @GetMapping("/exception") + String exception() { + int callCount = exceptionCallsCount.incrementAndGet(); + if (callCount % 2 != 0) { + throw new IllegalStateException("Test!"); + } + return "Hello World!"; + } + + @Bean + ReactiveLoadBalancer.Factory reactiveLoadBalancerFactory( + DiscoveryClient discoveryClient) { + return serviceId -> new DiscoveryClientBasedReactiveLoadBalancer(serviceId, + discoveryClient); + } + + @Bean + LoadBalancerRetryProperties loadBalancerRetryProperties() { + return new LoadBalancerRetryProperties(); + } + + @Bean + RetryableLoadBalancerExchangeFilterFunction exchangeFilterFunction( + LoadBalancerRetryProperties properties, + ReactiveLoadBalancer.Factory factory) { + return new RetryableLoadBalancerExchangeFilterFunction( + new RetryableExchangeFilterFunctionLoadBalancerRetryPolicy( + properties), + factory, properties); + } + + } + +} diff --git a/spring-cloud-commons/src/test/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableLoadBalancerExchangeFilterFunctionTests.java b/spring-cloud-commons/src/test/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableLoadBalancerExchangeFilterFunctionTests.java new file mode 100644 index 00000000..c0ed3a6d --- /dev/null +++ b/spring-cloud-commons/src/test/java/org/springframework/cloud/client/loadbalancer/reactive/RetryableLoadBalancerExchangeFilterFunctionTests.java @@ -0,0 +1,161 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.client.loadbalancer.reactive; + +import java.io.IOException; +import java.net.URI; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InOrder; +import reactor.core.publisher.Mono; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.LoadBalancerRetryProperties; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFunction; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Tests for {@link RetryableLoadBalancerExchangeFilterFunction}. + * + * @author Olga Maciaszek-Sharma + * @since 2.2.7 + */ +@SuppressWarnings("unchecked") +class RetryableLoadBalancerExchangeFilterFunctionTests { + + private final LoadBalancerRetryProperties properties = new LoadBalancerRetryProperties(); + + private final LoadBalancerRetryPolicy policy = new RetryableExchangeFilterFunctionLoadBalancerRetryPolicy( + properties); + + private final ReactiveLoadBalancer.Factory factory = mock( + ReactiveLoadBalancer.Factory.class); + + private final RetryableLoadBalancerExchangeFilterFunction filterFunction = new RetryableLoadBalancerExchangeFilterFunction( + policy, factory, properties); + + private final ClientRequest clientRequest = mock(ClientRequest.class); + + private final ExchangeFunction next = mock(ExchangeFunction.class); + + private final ClientResponse clientResponse = mock(ClientResponse.class); + + private final InOrder inOrder = inOrder(next, factory); + + @BeforeEach + void setUp() { + properties.setMaxRetriesOnSameServiceInstance(1); + properties.getRetryableStatusCodes().add(404); + when(clientRequest.url()).thenReturn(URI.create("http://test")); + when(factory.getInstance("test")).thenReturn(new TestReactiveLoadBalancer()); + when(clientRequest.headers()).thenReturn(new HttpHeaders()); + when(clientRequest.cookies()).thenReturn(new HttpHeaders()); + + } + + @Test + void shouldRetryOnSameAndNextServiceInstanceOnException() { + when(clientRequest.method()).thenReturn(HttpMethod.GET); + when(clientResponse.statusCode()).thenReturn(HttpStatus.OK); + when(next.exchange(any())) + .thenThrow(new IllegalStateException(new IOException())); + + try { + filterFunction.filter(clientRequest, next).subscribe(); + } + catch (Exception ignored) { + } + + inOrder.verify(factory, times(1)).getInstance(any()); + inOrder.verify(next, times(2)).exchange(any()); + inOrder.verify(factory, times(1)).getInstance(any()); + inOrder.verify(next, times(2)).exchange(any()); + } + + @Test + void shouldRetryOnSameAndNextServiceInstanceOnRetryableStatusCode() { + when(clientRequest.method()).thenReturn(HttpMethod.GET); + when(clientResponse.statusCode()).thenReturn(HttpStatus.NOT_FOUND); + when(next.exchange(any())).thenReturn(Mono.just(clientResponse)); + + filterFunction.filter(clientRequest, next).subscribe(); + + inOrder.verify(factory, times(1)).getInstance(any()); + inOrder.verify(next, times(2)).exchange(any()); + inOrder.verify(factory, times(1)).getInstance(any()); + inOrder.verify(next, times(2)).exchange(any()); + } + + @Test + void shouldNotRetryWhenNoRetryableExceptionOrStatusCode() { + when(clientRequest.method()).thenReturn(HttpMethod.GET); + when(clientResponse.statusCode()).thenReturn(HttpStatus.OK); + when(next.exchange(any())).thenReturn(Mono.just(clientResponse)); + + filterFunction.filter(clientRequest, next).subscribe(); + + verify(next, times(1)).exchange(any()); + verify(factory, times(1)).getInstance(any()); + } + + @Test + void shouldNotRetryOnMethodOtherThanGet() { + when(clientRequest.method()).thenReturn(HttpMethod.POST); + when(clientResponse.statusCode()).thenReturn(HttpStatus.NOT_FOUND); + when(next.exchange(any())).thenReturn(Mono.just(clientResponse)); + + filterFunction.filter(clientRequest, next).subscribe(); + + verify(next, times(1)).exchange(any()); + verify(factory, times(1)).getInstance(any()); + } + + @Test + void shouldRetryOnMethodOtherThanGetWhenEnabled() { + LoadBalancerRetryProperties properties = new LoadBalancerRetryProperties(); + properties.setRetryOnAllOperations(true); + properties.setMaxRetriesOnSameServiceInstance(1); + properties.getRetryableStatusCodes().add(404); + LoadBalancerRetryPolicy policy = new RetryableExchangeFilterFunctionLoadBalancerRetryPolicy( + properties); + RetryableLoadBalancerExchangeFilterFunction filterFunction = new RetryableLoadBalancerExchangeFilterFunction( + policy, factory, properties); + when(clientRequest.method()).thenReturn(HttpMethod.POST); + when(clientResponse.statusCode()).thenReturn(HttpStatus.NOT_FOUND); + when(next.exchange(any())).thenReturn(Mono.just(clientResponse)); + + filterFunction.filter(clientRequest, next).subscribe(); + + inOrder.verify(factory, times(1)).getInstance(any()); + inOrder.verify(next, times(2)).exchange(any()); + inOrder.verify(factory, times(1)).getInstance(any()); + inOrder.verify(next, times(2)).exchange(any()); + } + +} From d74cd35533763e8a5f2b760fd624ef1b9081beba Mon Sep 17 00:00:00 2001 From: buildmaster Date: Thu, 11 Feb 2021 13:09:01 +0000 Subject: [PATCH 2/4] Update SNAPSHOT to 2.2.7.RELEASE --- docs/pom.xml | 2 +- docs/src/main/asciidoc/_configprops.adoc | 80 +++++++++---------- pom.xml | 4 +- spring-cloud-commons-dependencies/pom.xml | 4 +- spring-cloud-commons/pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- spring-cloud-context/pom.xml | 2 +- spring-cloud-loadbalancer/pom.xml | 2 +- spring-cloud-starter-loadbalancer/pom.xml | 2 +- spring-cloud-starter/pom.xml | 2 +- spring-cloud-test-support/pom.xml | 2 +- 12 files changed, 53 insertions(+), 53 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index dc449138..801de8a8 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -8,7 +8,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.7.RELEASE pom Spring Cloud Commons Docs diff --git a/docs/src/main/asciidoc/_configprops.adoc b/docs/src/main/asciidoc/_configprops.adoc index dd749d13..f9f510d3 100644 --- a/docs/src/main/asciidoc/_configprops.adoc +++ b/docs/src/main/asciidoc/_configprops.adoc @@ -2,55 +2,55 @@ |Name | Default | Description |spring.cloud.compatibility-verifier.compatible-boot-versions | | Default accepted versions for the Spring Boot dependency. You can set {@code x} for the patch version if you don't want to specify a concrete value. Example: {@code 3.4.x} -|spring.cloud.compatibility-verifier.enabled | false | Enables creation of Spring Cloud compatibility verification. -|spring.cloud.config.allow-override | true | Flag to indicate that {@link #isOverrideSystemProperties() systemPropertiesOverride} can be used. Set to false to prevent users from changing the default accidentally. Default true. -|spring.cloud.config.override-none | false | Flag to indicate that when {@link #setAllowOverride(boolean) allowOverride} is true, external properties should take lowest priority and should not override any existing property sources (including local config files). Default false. -|spring.cloud.config.override-system-properties | true | Flag to indicate that the external properties should override system properties. Default true. -|spring.cloud.discovery.client.composite-indicator.enabled | true | Enables discovery client composite health indicator. -|spring.cloud.discovery.client.health-indicator.enabled | true | -|spring.cloud.discovery.client.health-indicator.include-description | false | +|spring.cloud.compatibility-verifier.enabled | `false` | Enables creation of Spring Cloud compatibility verification. +|spring.cloud.config.allow-override | `true` | Flag to indicate that {@link #isOverrideSystemProperties() systemPropertiesOverride} can be used. Set to false to prevent users from changing the default accidentally. Default true. +|spring.cloud.config.override-none | `false` | Flag to indicate that when {@link #setAllowOverride(boolean) allowOverride} is true, external properties should take lowest priority and should not override any existing property sources (including local config files). Default false. +|spring.cloud.config.override-system-properties | `true` | Flag to indicate that the external properties should override system properties. Default true. +|spring.cloud.discovery.client.composite-indicator.enabled | `true` | Enables discovery client composite health indicator. +|spring.cloud.discovery.client.health-indicator.enabled | `true` | +|spring.cloud.discovery.client.health-indicator.include-description | `false` | |spring.cloud.discovery.client.simple.instances | | |spring.cloud.discovery.client.simple.order | | -|spring.cloud.discovery.enabled | true | Enables discovery client health indicators. -|spring.cloud.features.enabled | true | Enables the features endpoint. -|spring.cloud.httpclientfactories.apache.enabled | true | Enables creation of Apache Http Client factory beans. -|spring.cloud.httpclientfactories.ok.enabled | true | Enables creation of OK Http Client factory beans. -|spring.cloud.hypermedia.refresh.fixed-delay | 5000 | -|spring.cloud.hypermedia.refresh.initial-delay | 10000 | -|spring.cloud.inetutils.default-hostname | localhost | The default hostname. Used in case of errors. -|spring.cloud.inetutils.default-ip-address | 127.0.0.1 | The default IP address. Used in case of errors. +|spring.cloud.discovery.enabled | `true` | Enables discovery client health indicators. +|spring.cloud.features.enabled | `true` | Enables the features endpoint. +|spring.cloud.httpclientfactories.apache.enabled | `true` | Enables creation of Apache Http Client factory beans. +|spring.cloud.httpclientfactories.ok.enabled | `true` | Enables creation of OK Http Client factory beans. +|spring.cloud.hypermedia.refresh.fixed-delay | `5000` | +|spring.cloud.hypermedia.refresh.initial-delay | `10000` | +|spring.cloud.inetutils.default-hostname | `localhost` | The default hostname. Used in case of errors. +|spring.cloud.inetutils.default-ip-address | `127.0.0.1` | The default IP address. Used in case of errors. |spring.cloud.inetutils.ignored-interfaces | | List of Java regular expressions for network interfaces that will be ignored. |spring.cloud.inetutils.preferred-networks | | List of Java regular expressions for network addresses that will be preferred. -|spring.cloud.inetutils.timeout-seconds | 1 | Timeout, in seconds, for calculating hostname. -|spring.cloud.inetutils.use-only-site-local-interfaces | false | Whether to use only interfaces with site local addresses. See {@link InetAddress#isSiteLocalAddress()} for more details. +|spring.cloud.inetutils.timeout-seconds | `1` | Timeout, in seconds, for calculating hostname. +|spring.cloud.inetutils.use-only-site-local-interfaces | `false` | Whether to use only interfaces with site local addresses. See {@link InetAddress#isSiteLocalAddress()} for more details. |spring.cloud.loadbalancer.cache.caffeine.spec | | The spec to use to create caches. See CaffeineSpec for more details on the spec format. -|spring.cloud.loadbalancer.cache.capacity | 256 | Initial cache capacity expressed as int. -|spring.cloud.loadbalancer.cache.enabled | true | Enables Spring Cloud LoadBalancer caching mechanism. -|spring.cloud.loadbalancer.cache.ttl | 35s | Time To Live - time counted from writing of the record, after which cache entries are expired, expressed as a {@link Duration}. The property {@link String} has to be in keeping with the appropriate syntax as specified in Spring Boot StringToDurationConverter. @see StringToDurationConverter.java -|spring.cloud.loadbalancer.health-check.initial-delay | 0 | Initial delay value for the HealthCheck scheduler. -|spring.cloud.loadbalancer.health-check.interval | 25s | Interval for rerunning the HealthCheck scheduler. +|spring.cloud.loadbalancer.cache.capacity | `256` | Initial cache capacity expressed as int. +|spring.cloud.loadbalancer.cache.enabled | `true` | Enables Spring Cloud LoadBalancer caching mechanism. +|spring.cloud.loadbalancer.cache.ttl | `35s` | Time To Live - time counted from writing of the record, after which cache entries are expired, expressed as a {@link Duration}. The property {@link String} has to be in keeping with the appropriate syntax as specified in Spring Boot StringToDurationConverter. @see StringToDurationConverter.java +|spring.cloud.loadbalancer.health-check.initial-delay | `0` | Initial delay value for the HealthCheck scheduler. +|spring.cloud.loadbalancer.health-check.interval | `25s` | Interval for rerunning the HealthCheck scheduler. |spring.cloud.loadbalancer.health-check.path | | -|spring.cloud.loadbalancer.health-check.refetch-instances | false | Indicates whether the instances should be refetched by the HealthCheckServiceInstanceListSupplier. This can be used if the instances can be updated and the underlying delegate does not provide an ongoing flux. -|spring.cloud.loadbalancer.health-check.refetch-instances-interval | 25s | Interval for refetching available service instances. -|spring.cloud.loadbalancer.health-check.repeat-health-check | true | Indicates whether health checks should keep repeating. It might be useful to set it to false if periodically refetching the instances, as every refetch will also trigger a healthcheck. -|spring.cloud.loadbalancer.retry.backoff.enabled | false | Indicates whether Reactor Retry backoffs should be applied. -|spring.cloud.loadbalancer.retry.backoff.jitter | 0.5 | Used to set {@link RetryBackoffSpec#jitter}. +|spring.cloud.loadbalancer.health-check.refetch-instances | `false` | Indicates whether the instances should be refetched by the HealthCheckServiceInstanceListSupplier. This can be used if the instances can be updated and the underlying delegate does not provide an ongoing flux. +|spring.cloud.loadbalancer.health-check.refetch-instances-interval | `25s` | Interval for refetching available service instances. +|spring.cloud.loadbalancer.health-check.repeat-health-check | `true` | Indicates whether health checks should keep repeating. It might be useful to set it to false if periodically refetching the instances, as every refetch will also trigger a healthcheck. +|spring.cloud.loadbalancer.retry.backoff.enabled | `false` | Indicates whether Reactor Retry backoffs should be applied. +|spring.cloud.loadbalancer.retry.backoff.jitter | `0.5` | Used to set {@link RetryBackoffSpec#jitter}. |spring.cloud.loadbalancer.retry.backoff.max-backoff | | Used to set {@link RetryBackoffSpec#maxBackoff}. -|spring.cloud.loadbalancer.retry.backoff.min-backoff | 5ms | Used to set {@link RetryBackoffSpec#minBackoff}. -|spring.cloud.loadbalancer.retry.enabled | true | -|spring.cloud.loadbalancer.retry.max-retries-on-next-service-instance | 1 | Number of retries to be executed on the next ServiceInstance. A ServiceInstance is chosen before each retry call. -|spring.cloud.loadbalancer.retry.max-retries-on-same-service-instance | 0 | Number of retries to be executed on the same ServiceInstance. -|spring.cloud.loadbalancer.retry.retry-on-all-operations | false | Indicates retries should be attempted on operations other than {@link HttpMethod#GET}. +|spring.cloud.loadbalancer.retry.backoff.min-backoff | `5ms` | Used to set {@link RetryBackoffSpec#minBackoff}. +|spring.cloud.loadbalancer.retry.enabled | `true` | +|spring.cloud.loadbalancer.retry.max-retries-on-next-service-instance | `1` | Number of retries to be executed on the next ServiceInstance. A ServiceInstance is chosen before each retry call. +|spring.cloud.loadbalancer.retry.max-retries-on-same-service-instance | `0` | Number of retries to be executed on the same ServiceInstance. +|spring.cloud.loadbalancer.retry.retry-on-all-operations | `false` | Indicates retries should be attempted on operations other than {@link HttpMethod#GET}. |spring.cloud.loadbalancer.retry.retryable-status-codes | | A {@link Set} of status codes that should trigger a retry. -|spring.cloud.loadbalancer.ribbon.enabled | true | Causes `RibbonLoadBalancerClient` to be used by default. +|spring.cloud.loadbalancer.ribbon.enabled | `true` | Causes `RibbonLoadBalancerClient` to be used by default. |spring.cloud.loadbalancer.service-discovery.timeout | | String representation of Duration of the timeout for calls to service discovery. |spring.cloud.loadbalancer.zone | | Spring Cloud LoadBalancer zone. -|spring.cloud.refresh.enabled | true | Enables autoconfiguration for the refresh scope and associated features. -|spring.cloud.refresh.extra-refreshable | true | Additional class names for beans to post process into refresh scope. -|spring.cloud.refresh.never-refreshable | true | Comma separated list of class names for beans to never be refreshed or rebound. -|spring.cloud.service-registry.auto-registration.enabled | true | Whether service auto-registration is enabled. Defaults to true. -|spring.cloud.service-registry.auto-registration.fail-fast | false | Whether startup fails if there is no AutoServiceRegistration. Defaults to false. -|spring.cloud.service-registry.auto-registration.register-management | true | Whether to register the management as a service. Defaults to true. -|spring.cloud.util.enabled | true | Enables creation of Spring Cloud utility beans. +|spring.cloud.refresh.enabled | `true` | Enables autoconfiguration for the refresh scope and associated features. +|spring.cloud.refresh.extra-refreshable | `true` | Additional class names for beans to post process into refresh scope. +|spring.cloud.refresh.never-refreshable | `true` | Comma separated list of class names for beans to never be refreshed or rebound. +|spring.cloud.service-registry.auto-registration.enabled | `true` | Whether service auto-registration is enabled. Defaults to true. +|spring.cloud.service-registry.auto-registration.fail-fast | `false` | Whether startup fails if there is no AutoServiceRegistration. Defaults to false. +|spring.cloud.service-registry.auto-registration.register-management | `true` | Whether to register the management as a service. Defaults to true. +|spring.cloud.util.enabled | `true` | Enables creation of Spring Cloud utility beans. |=== \ No newline at end of file diff --git a/pom.xml b/pom.xml index 334fb2c0..d1222657 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.7.RELEASE pom Spring Cloud Commons Parent Spring Cloud Commons Parent @@ -13,7 +13,7 @@ org.springframework.cloud spring-cloud-build - 2.3.1.RELEASE + 2.3.2.RELEASE diff --git a/spring-cloud-commons-dependencies/pom.xml b/spring-cloud-commons-dependencies/pom.xml index 1bcfb91e..6718892b 100644 --- a/spring-cloud-commons-dependencies/pom.xml +++ b/spring-cloud-commons-dependencies/pom.xml @@ -6,11 +6,11 @@ spring-cloud-dependencies-parent org.springframework.cloud - 2.3.2.BUILD-SNAPSHOT + 2.3.2.RELEASE spring-cloud-commons-dependencies - 2.2.7.BUILD-SNAPSHOT + 2.2.7.RELEASE pom spring-cloud-commons-dependencies Spring Cloud Commons Dependencies diff --git a/spring-cloud-commons/pom.xml b/spring-cloud-commons/pom.xml index cb89e0db..a95a0411 100644 --- a/spring-cloud-commons/pom.xml +++ b/spring-cloud-commons/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.7.RELEASE .. spring-cloud-commons diff --git a/spring-cloud-context-integration-tests/pom.xml b/spring-cloud-context-integration-tests/pom.xml index eda90830..860f0940 100644 --- a/spring-cloud-context-integration-tests/pom.xml +++ b/spring-cloud-context-integration-tests/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.7.RELEASE .. spring-cloud-context-integration-tests diff --git a/spring-cloud-context-webflux-integration-tests/pom.xml b/spring-cloud-context-webflux-integration-tests/pom.xml index 762b5879..b49f3440 100644 --- a/spring-cloud-context-webflux-integration-tests/pom.xml +++ b/spring-cloud-context-webflux-integration-tests/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.7.RELEASE .. spring-cloud-context-webflux-integration-tests diff --git a/spring-cloud-context/pom.xml b/spring-cloud-context/pom.xml index 953dcb54..42614412 100644 --- a/spring-cloud-context/pom.xml +++ b/spring-cloud-context/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.7.RELEASE .. spring-cloud-context diff --git a/spring-cloud-loadbalancer/pom.xml b/spring-cloud-loadbalancer/pom.xml index 81da2bf7..b3785b33 100644 --- a/spring-cloud-loadbalancer/pom.xml +++ b/spring-cloud-loadbalancer/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.7.RELEASE .. spring-cloud-loadbalancer diff --git a/spring-cloud-starter-loadbalancer/pom.xml b/spring-cloud-starter-loadbalancer/pom.xml index 014386a2..eaffa72a 100644 --- a/spring-cloud-starter-loadbalancer/pom.xml +++ b/spring-cloud-starter-loadbalancer/pom.xml @@ -5,7 +5,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.7.RELEASE .. 4.0.0 diff --git a/spring-cloud-starter/pom.xml b/spring-cloud-starter/pom.xml index 571de16f..fc8a2034 100644 --- a/spring-cloud-starter/pom.xml +++ b/spring-cloud-starter/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.7.RELEASE spring-cloud-starter spring-cloud-starter diff --git a/spring-cloud-test-support/pom.xml b/spring-cloud-test-support/pom.xml index e2924b0f..cbb9c682 100644 --- a/spring-cloud-test-support/pom.xml +++ b/spring-cloud-test-support/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.7.RELEASE .. spring-cloud-test-support From c8d0e7f13d299f46555aaa8d73343ff0d0facaa3 Mon Sep 17 00:00:00 2001 From: buildmaster Date: Thu, 11 Feb 2021 13:11:52 +0000 Subject: [PATCH 3/4] Going back to snapshots --- docs/pom.xml | 2 +- docs/src/main/asciidoc/_configprops.adoc | 80 +++++++++---------- pom.xml | 4 +- spring-cloud-commons-dependencies/pom.xml | 4 +- spring-cloud-commons/pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- spring-cloud-context/pom.xml | 2 +- spring-cloud-loadbalancer/pom.xml | 2 +- spring-cloud-starter-loadbalancer/pom.xml | 2 +- spring-cloud-starter/pom.xml | 2 +- spring-cloud-test-support/pom.xml | 2 +- 12 files changed, 53 insertions(+), 53 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index 801de8a8..dc449138 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -8,7 +8,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.RELEASE + 2.2.7.BUILD-SNAPSHOT pom Spring Cloud Commons Docs diff --git a/docs/src/main/asciidoc/_configprops.adoc b/docs/src/main/asciidoc/_configprops.adoc index f9f510d3..dd749d13 100644 --- a/docs/src/main/asciidoc/_configprops.adoc +++ b/docs/src/main/asciidoc/_configprops.adoc @@ -2,55 +2,55 @@ |Name | Default | Description |spring.cloud.compatibility-verifier.compatible-boot-versions | | Default accepted versions for the Spring Boot dependency. You can set {@code x} for the patch version if you don't want to specify a concrete value. Example: {@code 3.4.x} -|spring.cloud.compatibility-verifier.enabled | `false` | Enables creation of Spring Cloud compatibility verification. -|spring.cloud.config.allow-override | `true` | Flag to indicate that {@link #isOverrideSystemProperties() systemPropertiesOverride} can be used. Set to false to prevent users from changing the default accidentally. Default true. -|spring.cloud.config.override-none | `false` | Flag to indicate that when {@link #setAllowOverride(boolean) allowOverride} is true, external properties should take lowest priority and should not override any existing property sources (including local config files). Default false. -|spring.cloud.config.override-system-properties | `true` | Flag to indicate that the external properties should override system properties. Default true. -|spring.cloud.discovery.client.composite-indicator.enabled | `true` | Enables discovery client composite health indicator. -|spring.cloud.discovery.client.health-indicator.enabled | `true` | -|spring.cloud.discovery.client.health-indicator.include-description | `false` | +|spring.cloud.compatibility-verifier.enabled | false | Enables creation of Spring Cloud compatibility verification. +|spring.cloud.config.allow-override | true | Flag to indicate that {@link #isOverrideSystemProperties() systemPropertiesOverride} can be used. Set to false to prevent users from changing the default accidentally. Default true. +|spring.cloud.config.override-none | false | Flag to indicate that when {@link #setAllowOverride(boolean) allowOverride} is true, external properties should take lowest priority and should not override any existing property sources (including local config files). Default false. +|spring.cloud.config.override-system-properties | true | Flag to indicate that the external properties should override system properties. Default true. +|spring.cloud.discovery.client.composite-indicator.enabled | true | Enables discovery client composite health indicator. +|spring.cloud.discovery.client.health-indicator.enabled | true | +|spring.cloud.discovery.client.health-indicator.include-description | false | |spring.cloud.discovery.client.simple.instances | | |spring.cloud.discovery.client.simple.order | | -|spring.cloud.discovery.enabled | `true` | Enables discovery client health indicators. -|spring.cloud.features.enabled | `true` | Enables the features endpoint. -|spring.cloud.httpclientfactories.apache.enabled | `true` | Enables creation of Apache Http Client factory beans. -|spring.cloud.httpclientfactories.ok.enabled | `true` | Enables creation of OK Http Client factory beans. -|spring.cloud.hypermedia.refresh.fixed-delay | `5000` | -|spring.cloud.hypermedia.refresh.initial-delay | `10000` | -|spring.cloud.inetutils.default-hostname | `localhost` | The default hostname. Used in case of errors. -|spring.cloud.inetutils.default-ip-address | `127.0.0.1` | The default IP address. Used in case of errors. +|spring.cloud.discovery.enabled | true | Enables discovery client health indicators. +|spring.cloud.features.enabled | true | Enables the features endpoint. +|spring.cloud.httpclientfactories.apache.enabled | true | Enables creation of Apache Http Client factory beans. +|spring.cloud.httpclientfactories.ok.enabled | true | Enables creation of OK Http Client factory beans. +|spring.cloud.hypermedia.refresh.fixed-delay | 5000 | +|spring.cloud.hypermedia.refresh.initial-delay | 10000 | +|spring.cloud.inetutils.default-hostname | localhost | The default hostname. Used in case of errors. +|spring.cloud.inetutils.default-ip-address | 127.0.0.1 | The default IP address. Used in case of errors. |spring.cloud.inetutils.ignored-interfaces | | List of Java regular expressions for network interfaces that will be ignored. |spring.cloud.inetutils.preferred-networks | | List of Java regular expressions for network addresses that will be preferred. -|spring.cloud.inetutils.timeout-seconds | `1` | Timeout, in seconds, for calculating hostname. -|spring.cloud.inetutils.use-only-site-local-interfaces | `false` | Whether to use only interfaces with site local addresses. See {@link InetAddress#isSiteLocalAddress()} for more details. +|spring.cloud.inetutils.timeout-seconds | 1 | Timeout, in seconds, for calculating hostname. +|spring.cloud.inetutils.use-only-site-local-interfaces | false | Whether to use only interfaces with site local addresses. See {@link InetAddress#isSiteLocalAddress()} for more details. |spring.cloud.loadbalancer.cache.caffeine.spec | | The spec to use to create caches. See CaffeineSpec for more details on the spec format. -|spring.cloud.loadbalancer.cache.capacity | `256` | Initial cache capacity expressed as int. -|spring.cloud.loadbalancer.cache.enabled | `true` | Enables Spring Cloud LoadBalancer caching mechanism. -|spring.cloud.loadbalancer.cache.ttl | `35s` | Time To Live - time counted from writing of the record, after which cache entries are expired, expressed as a {@link Duration}. The property {@link String} has to be in keeping with the appropriate syntax as specified in Spring Boot StringToDurationConverter. @see StringToDurationConverter.java -|spring.cloud.loadbalancer.health-check.initial-delay | `0` | Initial delay value for the HealthCheck scheduler. -|spring.cloud.loadbalancer.health-check.interval | `25s` | Interval for rerunning the HealthCheck scheduler. +|spring.cloud.loadbalancer.cache.capacity | 256 | Initial cache capacity expressed as int. +|spring.cloud.loadbalancer.cache.enabled | true | Enables Spring Cloud LoadBalancer caching mechanism. +|spring.cloud.loadbalancer.cache.ttl | 35s | Time To Live - time counted from writing of the record, after which cache entries are expired, expressed as a {@link Duration}. The property {@link String} has to be in keeping with the appropriate syntax as specified in Spring Boot StringToDurationConverter. @see StringToDurationConverter.java +|spring.cloud.loadbalancer.health-check.initial-delay | 0 | Initial delay value for the HealthCheck scheduler. +|spring.cloud.loadbalancer.health-check.interval | 25s | Interval for rerunning the HealthCheck scheduler. |spring.cloud.loadbalancer.health-check.path | | -|spring.cloud.loadbalancer.health-check.refetch-instances | `false` | Indicates whether the instances should be refetched by the HealthCheckServiceInstanceListSupplier. This can be used if the instances can be updated and the underlying delegate does not provide an ongoing flux. -|spring.cloud.loadbalancer.health-check.refetch-instances-interval | `25s` | Interval for refetching available service instances. -|spring.cloud.loadbalancer.health-check.repeat-health-check | `true` | Indicates whether health checks should keep repeating. It might be useful to set it to false if periodically refetching the instances, as every refetch will also trigger a healthcheck. -|spring.cloud.loadbalancer.retry.backoff.enabled | `false` | Indicates whether Reactor Retry backoffs should be applied. -|spring.cloud.loadbalancer.retry.backoff.jitter | `0.5` | Used to set {@link RetryBackoffSpec#jitter}. +|spring.cloud.loadbalancer.health-check.refetch-instances | false | Indicates whether the instances should be refetched by the HealthCheckServiceInstanceListSupplier. This can be used if the instances can be updated and the underlying delegate does not provide an ongoing flux. +|spring.cloud.loadbalancer.health-check.refetch-instances-interval | 25s | Interval for refetching available service instances. +|spring.cloud.loadbalancer.health-check.repeat-health-check | true | Indicates whether health checks should keep repeating. It might be useful to set it to false if periodically refetching the instances, as every refetch will also trigger a healthcheck. +|spring.cloud.loadbalancer.retry.backoff.enabled | false | Indicates whether Reactor Retry backoffs should be applied. +|spring.cloud.loadbalancer.retry.backoff.jitter | 0.5 | Used to set {@link RetryBackoffSpec#jitter}. |spring.cloud.loadbalancer.retry.backoff.max-backoff | | Used to set {@link RetryBackoffSpec#maxBackoff}. -|spring.cloud.loadbalancer.retry.backoff.min-backoff | `5ms` | Used to set {@link RetryBackoffSpec#minBackoff}. -|spring.cloud.loadbalancer.retry.enabled | `true` | -|spring.cloud.loadbalancer.retry.max-retries-on-next-service-instance | `1` | Number of retries to be executed on the next ServiceInstance. A ServiceInstance is chosen before each retry call. -|spring.cloud.loadbalancer.retry.max-retries-on-same-service-instance | `0` | Number of retries to be executed on the same ServiceInstance. -|spring.cloud.loadbalancer.retry.retry-on-all-operations | `false` | Indicates retries should be attempted on operations other than {@link HttpMethod#GET}. +|spring.cloud.loadbalancer.retry.backoff.min-backoff | 5ms | Used to set {@link RetryBackoffSpec#minBackoff}. +|spring.cloud.loadbalancer.retry.enabled | true | +|spring.cloud.loadbalancer.retry.max-retries-on-next-service-instance | 1 | Number of retries to be executed on the next ServiceInstance. A ServiceInstance is chosen before each retry call. +|spring.cloud.loadbalancer.retry.max-retries-on-same-service-instance | 0 | Number of retries to be executed on the same ServiceInstance. +|spring.cloud.loadbalancer.retry.retry-on-all-operations | false | Indicates retries should be attempted on operations other than {@link HttpMethod#GET}. |spring.cloud.loadbalancer.retry.retryable-status-codes | | A {@link Set} of status codes that should trigger a retry. -|spring.cloud.loadbalancer.ribbon.enabled | `true` | Causes `RibbonLoadBalancerClient` to be used by default. +|spring.cloud.loadbalancer.ribbon.enabled | true | Causes `RibbonLoadBalancerClient` to be used by default. |spring.cloud.loadbalancer.service-discovery.timeout | | String representation of Duration of the timeout for calls to service discovery. |spring.cloud.loadbalancer.zone | | Spring Cloud LoadBalancer zone. -|spring.cloud.refresh.enabled | `true` | Enables autoconfiguration for the refresh scope and associated features. -|spring.cloud.refresh.extra-refreshable | `true` | Additional class names for beans to post process into refresh scope. -|spring.cloud.refresh.never-refreshable | `true` | Comma separated list of class names for beans to never be refreshed or rebound. -|spring.cloud.service-registry.auto-registration.enabled | `true` | Whether service auto-registration is enabled. Defaults to true. -|spring.cloud.service-registry.auto-registration.fail-fast | `false` | Whether startup fails if there is no AutoServiceRegistration. Defaults to false. -|spring.cloud.service-registry.auto-registration.register-management | `true` | Whether to register the management as a service. Defaults to true. -|spring.cloud.util.enabled | `true` | Enables creation of Spring Cloud utility beans. +|spring.cloud.refresh.enabled | true | Enables autoconfiguration for the refresh scope and associated features. +|spring.cloud.refresh.extra-refreshable | true | Additional class names for beans to post process into refresh scope. +|spring.cloud.refresh.never-refreshable | true | Comma separated list of class names for beans to never be refreshed or rebound. +|spring.cloud.service-registry.auto-registration.enabled | true | Whether service auto-registration is enabled. Defaults to true. +|spring.cloud.service-registry.auto-registration.fail-fast | false | Whether startup fails if there is no AutoServiceRegistration. Defaults to false. +|spring.cloud.service-registry.auto-registration.register-management | true | Whether to register the management as a service. Defaults to true. +|spring.cloud.util.enabled | true | Enables creation of Spring Cloud utility beans. |=== \ No newline at end of file diff --git a/pom.xml b/pom.xml index d1222657..334fb2c0 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.springframework.cloud spring-cloud-commons-parent - 2.2.7.RELEASE + 2.2.7.BUILD-SNAPSHOT pom Spring Cloud Commons Parent Spring Cloud Commons Parent @@ -13,7 +13,7 @@ org.springframework.cloud spring-cloud-build - 2.3.2.RELEASE + 2.3.1.RELEASE diff --git a/spring-cloud-commons-dependencies/pom.xml b/spring-cloud-commons-dependencies/pom.xml index 6718892b..1bcfb91e 100644 --- a/spring-cloud-commons-dependencies/pom.xml +++ b/spring-cloud-commons-dependencies/pom.xml @@ -6,11 +6,11 @@ spring-cloud-dependencies-parent org.springframework.cloud - 2.3.2.RELEASE + 2.3.2.BUILD-SNAPSHOT spring-cloud-commons-dependencies - 2.2.7.RELEASE + 2.2.7.BUILD-SNAPSHOT pom spring-cloud-commons-dependencies Spring Cloud Commons Dependencies diff --git a/spring-cloud-commons/pom.xml b/spring-cloud-commons/pom.xml index a95a0411..cb89e0db 100644 --- a/spring-cloud-commons/pom.xml +++ b/spring-cloud-commons/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.RELEASE + 2.2.7.BUILD-SNAPSHOT .. spring-cloud-commons diff --git a/spring-cloud-context-integration-tests/pom.xml b/spring-cloud-context-integration-tests/pom.xml index 860f0940..eda90830 100644 --- a/spring-cloud-context-integration-tests/pom.xml +++ b/spring-cloud-context-integration-tests/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.RELEASE + 2.2.7.BUILD-SNAPSHOT .. spring-cloud-context-integration-tests diff --git a/spring-cloud-context-webflux-integration-tests/pom.xml b/spring-cloud-context-webflux-integration-tests/pom.xml index b49f3440..762b5879 100644 --- a/spring-cloud-context-webflux-integration-tests/pom.xml +++ b/spring-cloud-context-webflux-integration-tests/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.RELEASE + 2.2.7.BUILD-SNAPSHOT .. spring-cloud-context-webflux-integration-tests diff --git a/spring-cloud-context/pom.xml b/spring-cloud-context/pom.xml index 42614412..953dcb54 100644 --- a/spring-cloud-context/pom.xml +++ b/spring-cloud-context/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.RELEASE + 2.2.7.BUILD-SNAPSHOT .. spring-cloud-context diff --git a/spring-cloud-loadbalancer/pom.xml b/spring-cloud-loadbalancer/pom.xml index b3785b33..81da2bf7 100644 --- a/spring-cloud-loadbalancer/pom.xml +++ b/spring-cloud-loadbalancer/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.RELEASE + 2.2.7.BUILD-SNAPSHOT .. spring-cloud-loadbalancer diff --git a/spring-cloud-starter-loadbalancer/pom.xml b/spring-cloud-starter-loadbalancer/pom.xml index eaffa72a..014386a2 100644 --- a/spring-cloud-starter-loadbalancer/pom.xml +++ b/spring-cloud-starter-loadbalancer/pom.xml @@ -5,7 +5,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.RELEASE + 2.2.7.BUILD-SNAPSHOT .. 4.0.0 diff --git a/spring-cloud-starter/pom.xml b/spring-cloud-starter/pom.xml index fc8a2034..571de16f 100644 --- a/spring-cloud-starter/pom.xml +++ b/spring-cloud-starter/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.RELEASE + 2.2.7.BUILD-SNAPSHOT spring-cloud-starter spring-cloud-starter diff --git a/spring-cloud-test-support/pom.xml b/spring-cloud-test-support/pom.xml index cbb9c682..e2924b0f 100644 --- a/spring-cloud-test-support/pom.xml +++ b/spring-cloud-test-support/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.RELEASE + 2.2.7.BUILD-SNAPSHOT .. spring-cloud-test-support From 3aff1bea0d3f5ab3d1f2b70739f5b84ce7d9ced4 Mon Sep 17 00:00:00 2001 From: buildmaster Date: Thu, 11 Feb 2021 13:11:53 +0000 Subject: [PATCH 4/4] Bumping versions to 2.2.8.BUILD-SNAPSHOT after release --- docs/pom.xml | 2 +- pom.xml | 4 ++-- spring-cloud-commons-dependencies/pom.xml | 4 ++-- spring-cloud-commons/pom.xml | 2 +- spring-cloud-context-integration-tests/pom.xml | 2 +- spring-cloud-context-webflux-integration-tests/pom.xml | 2 +- spring-cloud-context/pom.xml | 2 +- spring-cloud-loadbalancer/pom.xml | 2 +- spring-cloud-starter-loadbalancer/pom.xml | 2 +- spring-cloud-starter/pom.xml | 2 +- spring-cloud-test-support/pom.xml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/pom.xml b/docs/pom.xml index dc449138..a0dc25a2 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -8,7 +8,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.8.BUILD-SNAPSHOT pom Spring Cloud Commons Docs diff --git a/pom.xml b/pom.xml index 334fb2c0..cef40c4b 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.8.BUILD-SNAPSHOT pom Spring Cloud Commons Parent Spring Cloud Commons Parent @@ -13,7 +13,7 @@ org.springframework.cloud spring-cloud-build - 2.3.1.RELEASE + 2.3.2.RELEASE diff --git a/spring-cloud-commons-dependencies/pom.xml b/spring-cloud-commons-dependencies/pom.xml index 1bcfb91e..db3c3c90 100644 --- a/spring-cloud-commons-dependencies/pom.xml +++ b/spring-cloud-commons-dependencies/pom.xml @@ -6,11 +6,11 @@ spring-cloud-dependencies-parent org.springframework.cloud - 2.3.2.BUILD-SNAPSHOT + 2.3.3.BUILD-SNAPSHOT spring-cloud-commons-dependencies - 2.2.7.BUILD-SNAPSHOT + 2.2.8.BUILD-SNAPSHOT pom spring-cloud-commons-dependencies Spring Cloud Commons Dependencies diff --git a/spring-cloud-commons/pom.xml b/spring-cloud-commons/pom.xml index cb89e0db..bfa7ee1b 100644 --- a/spring-cloud-commons/pom.xml +++ b/spring-cloud-commons/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.8.BUILD-SNAPSHOT .. spring-cloud-commons diff --git a/spring-cloud-context-integration-tests/pom.xml b/spring-cloud-context-integration-tests/pom.xml index eda90830..81106b25 100644 --- a/spring-cloud-context-integration-tests/pom.xml +++ b/spring-cloud-context-integration-tests/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.8.BUILD-SNAPSHOT .. spring-cloud-context-integration-tests diff --git a/spring-cloud-context-webflux-integration-tests/pom.xml b/spring-cloud-context-webflux-integration-tests/pom.xml index 762b5879..3ea93d51 100644 --- a/spring-cloud-context-webflux-integration-tests/pom.xml +++ b/spring-cloud-context-webflux-integration-tests/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.8.BUILD-SNAPSHOT .. spring-cloud-context-webflux-integration-tests diff --git a/spring-cloud-context/pom.xml b/spring-cloud-context/pom.xml index 953dcb54..20d8cb13 100644 --- a/spring-cloud-context/pom.xml +++ b/spring-cloud-context/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.8.BUILD-SNAPSHOT .. spring-cloud-context diff --git a/spring-cloud-loadbalancer/pom.xml b/spring-cloud-loadbalancer/pom.xml index 81da2bf7..055d14b2 100644 --- a/spring-cloud-loadbalancer/pom.xml +++ b/spring-cloud-loadbalancer/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.8.BUILD-SNAPSHOT .. spring-cloud-loadbalancer diff --git a/spring-cloud-starter-loadbalancer/pom.xml b/spring-cloud-starter-loadbalancer/pom.xml index 014386a2..84c457d0 100644 --- a/spring-cloud-starter-loadbalancer/pom.xml +++ b/spring-cloud-starter-loadbalancer/pom.xml @@ -5,7 +5,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.8.BUILD-SNAPSHOT .. 4.0.0 diff --git a/spring-cloud-starter/pom.xml b/spring-cloud-starter/pom.xml index 571de16f..be60f7bd 100644 --- a/spring-cloud-starter/pom.xml +++ b/spring-cloud-starter/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.8.BUILD-SNAPSHOT spring-cloud-starter spring-cloud-starter diff --git a/spring-cloud-test-support/pom.xml b/spring-cloud-test-support/pom.xml index e2924b0f..80f7d887 100644 --- a/spring-cloud-test-support/pom.xml +++ b/spring-cloud-test-support/pom.xml @@ -7,7 +7,7 @@ org.springframework.cloud spring-cloud-commons-parent - 2.2.7.BUILD-SNAPSHOT + 2.2.8.BUILD-SNAPSHOT .. spring-cloud-test-support