-
Notifications
You must be signed in to change notification settings - Fork 146
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Retry mechanism #577
base: 3.1.x
Are you sure you want to change the base?
Retry mechanism #577
Changes from 2 commits
155cade
d6e53e5
2475452
2fa16a6
2039cd5
b3edca9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xmlns="http://maven.apache.org/POM/4.0.0" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>org.springframework.cloud</groupId> | ||
<artifactId>spring-cloud-vault-parent</artifactId> | ||
<version>3.0.2-SNAPSHOT</version> | ||
<relativePath>..</relativePath> | ||
</parent> | ||
|
||
<artifactId>spring-cloud-vault-config-tests</artifactId> | ||
<name>Spring Cloud Vault Config Tests</name> | ||
<description>Module for testing spring-cloud-vault-config with a limited number of dependencies</description> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.springframework.cloud</groupId> | ||
<artifactId>spring-cloud-starter-vault-config</artifactId> | ||
<version>${project.version}</version> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-test</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.junit.vintage</groupId> | ||
<artifactId>junit-vintage-engine</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-deploy-plugin</artifactId> | ||
<configuration> | ||
<!--test module only - should not be deployed --> | ||
<skip>true</skip> | ||
</configuration> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-enforcer-plugin</artifactId> | ||
<executions> | ||
<execution> | ||
<id>enforce-banned-dependencies</id> | ||
<goals> | ||
<goal>enforce</goal> | ||
</goals> | ||
<configuration> | ||
<rules> | ||
<bannedDependencies> | ||
<excludes> | ||
<exclude>org.springframework.retry:spring-retry</exclude> | ||
</excludes> | ||
</bannedDependencies> | ||
</rules> | ||
<fail>true</fail> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* | ||
* Copyright 2016-2020 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.vault.config; | ||
|
||
import org.junit.Test; | ||
import org.springframework.boot.autoconfigure.AutoConfigurations; | ||
import org.springframework.boot.test.context.runner.ApplicationContextRunner; | ||
import org.springframework.http.HttpMethod; | ||
import org.springframework.http.client.ClientHttpRequest; | ||
import org.springframework.http.client.ClientHttpRequestFactory; | ||
import org.springframework.vault.config.AbstractVaultConfiguration; | ||
|
||
import java.net.URI; | ||
|
||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat; | ||
|
||
/** | ||
* Tests without spring-retry on the classpath to be sure there is no hard dependency | ||
*/ | ||
public class VaultAutoConfigurationRetryUnavailableTests { | ||
|
||
private ApplicationContextRunner contextRunner = new ApplicationContextRunner() | ||
.withConfiguration(AutoConfigurations.of(VaultAutoConfiguration.class)); | ||
|
||
@Test | ||
public void shouldNotBeConfigured() { | ||
|
||
this.contextRunner.withPropertyValues("spring.cloud.vault.kv.enabled=false", | ||
"spring.cloud.vault.fail-fast=true", "spring.cloud.vault.token=foo").run(context -> { | ||
assertThat(context.containsBean("vaultRetryOperations")).isFalse(); | ||
AbstractVaultConfiguration.ClientFactoryWrapper clientFactoryWrapper = context | ||
.getBean(AbstractVaultConfiguration.ClientFactoryWrapper.class); | ||
ClientHttpRequestFactory requestFactory = clientFactoryWrapper.getClientHttpRequestFactory(); | ||
ClientHttpRequest request = requestFactory.createRequest(new URI("https://spring.io/"), | ||
HttpMethod.GET); | ||
assertThat(request instanceof RetryableClientHttpRequest).isFalse(); | ||
}); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* | ||
* Copyright 2016-2020 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.vault.config; | ||
|
||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.client.ClientHttpRequest; | ||
import org.springframework.http.client.ClientHttpResponse; | ||
import org.springframework.retry.RetryOperations; | ||
|
||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.net.URI; | ||
|
||
/** | ||
* {@link ClientHttpRequest} configured with retry support | ||
*/ | ||
class RetryableClientHttpRequest implements ClientHttpRequest { | ||
|
||
private final ClientHttpRequest delegateRequest; | ||
|
||
private final RetryOperations retryOperations; | ||
|
||
RetryableClientHttpRequest(ClientHttpRequest request, RetryOperations retryOperations) { | ||
this.delegateRequest = request; | ||
this.retryOperations = retryOperations; | ||
} | ||
|
||
@Override | ||
public ClientHttpResponse execute() throws IOException { | ||
return retryOperations.execute(retryContext -> delegateRequest.execute()); | ||
} | ||
|
||
@Override | ||
public OutputStream getBody() throws IOException { | ||
return delegateRequest.getBody(); | ||
} | ||
|
||
@Override | ||
public String getMethodValue() { | ||
return delegateRequest.getMethodValue(); | ||
} | ||
|
||
@Override | ||
public URI getURI() { | ||
return delegateRequest.getURI(); | ||
} | ||
|
||
@Override | ||
public HttpHeaders getHeaders() { | ||
return delegateRequest.getHeaders(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -130,6 +130,8 @@ public class VaultProperties implements EnvironmentAware { | |
|
||
private Session session = new Session(); | ||
|
||
private Retry retry = new Retry(); | ||
|
||
/** | ||
* Application name for AppId authentication. | ||
*/ | ||
|
@@ -350,6 +352,14 @@ public void setAuthentication(AuthenticationMethod authentication) { | |
this.authentication = authentication; | ||
} | ||
|
||
public Retry getRetry() { | ||
return this.retry; | ||
} | ||
|
||
public void setRetry(Retry retry) { | ||
this.retry = retry; | ||
} | ||
|
||
/** | ||
* Enumeration of authentication methods. | ||
*/ | ||
|
@@ -1287,4 +1297,65 @@ public void setExpiryThreshold(Duration expiryThreshold) { | |
|
||
} | ||
|
||
/** | ||
* Vault retry configuration | ||
* | ||
* @since 3.0.2 | ||
*/ | ||
public static class Retry { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's mount retry properties externally, similar to https://github.com/spring-cloud/spring-cloud-config/blob/master/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/RetryProperties.java. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implemented in updated changes. |
||
|
||
/** | ||
* Initial retry interval in milliseconds. | ||
*/ | ||
long initialInterval = 1000; | ||
|
||
/** | ||
* Multiplier for next interval. | ||
*/ | ||
double multiplier = 1.1; | ||
|
||
/** | ||
* Maximum interval for backoff. | ||
*/ | ||
long maxInterval = 2000; | ||
|
||
/** | ||
* Maximum number of attempts. | ||
*/ | ||
int maxAttempts = 6; | ||
|
||
public long getInitialInterval() { | ||
return this.initialInterval; | ||
} | ||
|
||
public void setInitialInterval(long initialInterval) { | ||
this.initialInterval = initialInterval; | ||
} | ||
|
||
public double getMultiplier() { | ||
return this.multiplier; | ||
} | ||
|
||
public void setMultiplier(double multiplier) { | ||
this.multiplier = multiplier; | ||
} | ||
|
||
public long getMaxInterval() { | ||
return this.maxInterval; | ||
} | ||
|
||
public void setMaxInterval(long maxInterval) { | ||
this.maxInterval = maxInterval; | ||
} | ||
|
||
public int getMaxAttempts() { | ||
return this.maxAttempts; | ||
} | ||
|
||
public void setMaxAttempts(int maxAttempts) { | ||
this.maxAttempts = maxAttempts; | ||
} | ||
|
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/* | ||
* Copyright 2018-2020 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.vault.config; | ||
|
||
import org.springframework.http.client.ClientHttpRequest; | ||
import org.springframework.http.client.ClientHttpRequestFactory; | ||
import org.springframework.retry.backoff.ExponentialBackOffPolicy; | ||
import org.springframework.retry.policy.SimpleRetryPolicy; | ||
import org.springframework.retry.support.RetryTemplate; | ||
|
||
/** | ||
* Util class for building objects that rely on spring-retry | ||
*/ | ||
final class VaultRetryUtil { | ||
|
||
private VaultRetryUtil() { | ||
|
||
} | ||
|
||
static ClientHttpRequestFactory createRetryableClientHttpRequestFactory(VaultProperties vaultProperties, | ||
ClientHttpRequestFactory delegate) { | ||
VaultProperties.Retry retryProperties = vaultProperties.getRetry(); | ||
RetryTemplate retryTemplate = new RetryTemplate(); | ||
|
||
ExponentialBackOffPolicy policy = new ExponentialBackOffPolicy(); | ||
policy.setInitialInterval(retryProperties.getInitialInterval()); | ||
policy.setMultiplier(retryProperties.getMultiplier()); | ||
policy.setMaxInterval(retryProperties.getMaxInterval()); | ||
|
||
retryTemplate.setBackOffPolicy(policy); | ||
retryTemplate.setRetryPolicy(new SimpleRetryPolicy(retryProperties.getMaxAttempts())); | ||
|
||
return (uri, httpMethod) -> retryTemplate.execute(retryContext -> { | ||
ClientHttpRequest request = delegate.createRequest(uri, httpMethod); | ||
return new RetryableClientHttpRequest(request, retryTemplate); | ||
}); | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would make sense to reuse potentially existing
RetryTemplate
beans (or instances when using the ConfigData boostrapper, see https://github.com/spring-cloud/spring-cloud-config/blob/master/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/ConfigClientRetryBootstrapper.java)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New changes re-use existing RetryTemplate beans