-
Notifications
You must be signed in to change notification settings - Fork 146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Retry mechanism #577
base: 3.1.x
Are you sure you want to change the base?
Retry mechanism #577
Changes from 4 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,81 @@ | ||
/* | ||
* Copyright 2014-2019 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.boot.context.properties.ConfigurationProperties; | ||
|
||
@ConfigurationProperties(RetryProperties.PREFIX) | ||
public class RetryProperties { | ||
|
||
/** | ||
* ConfigurationProperties prefix. | ||
*/ | ||
public static final String PREFIX = "spring.cloud.vault.retry"; | ||
|
||
/** | ||
* 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,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 |
---|---|---|
|
@@ -19,7 +19,10 @@ | |
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import org.apache.commons.logging.Log; | ||
import org.apache.commons.logging.LogFactory; | ||
import org.springframework.beans.factory.DisposableBean; | ||
import org.springframework.beans.factory.InitializingBean; | ||
import org.springframework.beans.factory.ObjectFactory; | ||
|
@@ -37,8 +40,10 @@ | |
import org.springframework.core.annotation.Order; | ||
import org.springframework.core.task.AsyncTaskExecutor; | ||
import org.springframework.http.client.ClientHttpRequestFactory; | ||
import org.springframework.retry.support.RetryTemplate; | ||
import org.springframework.scheduling.TaskScheduler; | ||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; | ||
import org.springframework.util.ClassUtils; | ||
import org.springframework.vault.authentication.ClientAuthentication; | ||
import org.springframework.vault.authentication.LifecycleAwareSessionManager; | ||
import org.springframework.vault.authentication.SessionManager; | ||
|
@@ -64,14 +69,20 @@ | |
*/ | ||
@Configuration(proxyBeanMethods = false) | ||
@ConditionalOnProperty(name = "spring.cloud.vault.enabled", matchIfMissing = true) | ||
@EnableConfigurationProperties(VaultProperties.class) | ||
@EnableConfigurationProperties({ VaultProperties.class, RetryProperties.class }) | ||
@Order(Ordered.LOWEST_PRECEDENCE - 5) | ||
public class VaultAutoConfiguration { | ||
|
||
private final Log log = LogFactory.getLog(getClass()); | ||
|
||
private static final String RETRY_TEMPLATE = "org.springframework.retry.support.RetryTemplate"; | ||
|
||
private final ConfigurableApplicationContext applicationContext; | ||
|
||
private final VaultProperties vaultProperties; | ||
|
||
private final RetryProperties retryProperties; | ||
|
||
private final VaultConfiguration configuration; | ||
|
||
private final VaultEndpointProvider endpointProvider; | ||
|
@@ -81,12 +92,13 @@ public class VaultAutoConfiguration { | |
private final List<RestTemplateRequestCustomizer<?>> requestCustomizers; | ||
|
||
public VaultAutoConfiguration(ConfigurableApplicationContext applicationContext, VaultProperties vaultProperties, | ||
ObjectProvider<VaultEndpointProvider> endpointProvider, | ||
RetryProperties retryProperties, ObjectProvider<VaultEndpointProvider> endpointProvider, | ||
ObjectProvider<List<RestTemplateCustomizer>> customizers, | ||
ObjectProvider<List<RestTemplateRequestCustomizer<?>>> requestCustomizers) { | ||
|
||
this.applicationContext = applicationContext; | ||
this.vaultProperties = vaultProperties; | ||
this.retryProperties = retryProperties; | ||
this.configuration = new VaultConfiguration(vaultProperties); | ||
|
||
VaultEndpointProvider provider = endpointProvider.getIfAvailable(); | ||
|
@@ -129,7 +141,21 @@ protected RestTemplateBuilder restTemplateBuilder(ClientHttpRequestFactory reque | |
@Bean | ||
@ConditionalOnMissingBean | ||
public ClientFactoryWrapper clientHttpRequestFactoryWrapper() { | ||
return new ClientFactoryWrapper(this.configuration.createClientHttpRequestFactory()); | ||
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. It would make sense to reuse potentially existing 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. New changes re-use existing RetryTemplate beans |
||
ClientHttpRequestFactory clientHttpRequestFactory = this.configuration.createClientHttpRequestFactory(); | ||
if (ClassUtils.isPresent(RETRY_TEMPLATE, getClass().getClassLoader()) && this.vaultProperties.isFailFast()) { | ||
Map<String, RetryTemplate> beans = applicationContext.getBeansOfType(RetryTemplate.class); | ||
if (!beans.isEmpty()) { | ||
Map.Entry<String, RetryTemplate> existingBean = beans.entrySet().stream().findFirst().get(); | ||
log.info("Using existing RestTemplate '" + existingBean.getKey() + "' for vault retries"); | ||
clientHttpRequestFactory = VaultRetryUtil | ||
.createRetryableClientHttpRequestFactory(existingBean.getValue(), clientHttpRequestFactory); | ||
} | ||
else { | ||
clientHttpRequestFactory = VaultRetryUtil.createRetryableClientHttpRequestFactory(retryProperties, | ||
clientHttpRequestFactory); | ||
} | ||
} | ||
return new ClientFactoryWrapper(clientHttpRequestFactory); | ||
} | ||
|
||
/** | ||
|
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.
This should read
spring.cloud.vault.retry.*
instead?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.
Great catch - fixed.