Skip to content

Commit

Permalink
Use random backoff policy for retry when using bootstrap. (spring-clo…
Browse files Browse the repository at this point in the history
…ud#2380)

Fixes spring-cloud#2379

Co-authored-by: Ryan Baxter <524254+ryanjbaxter@users.noreply.github.com>
  • Loading branch information
Ryan Baxter and ryanjbaxter authored Feb 1, 2024
1 parent fecaa1f commit 9e64b4c
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.annotation.Retryable;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.backoff.ExponentialRandomBackOffPolicy;
import org.springframework.retry.interceptor.RetryInterceptorBuilder;
import org.springframework.retry.interceptor.RetryOperationsInterceptor;

Expand Down Expand Up @@ -70,8 +72,12 @@ protected static class RetryConfiguration {
@Bean
@ConditionalOnMissingBean(name = "configServerRetryInterceptor")
public RetryOperationsInterceptor configServerRetryInterceptor(RetryProperties properties) {
return RetryInterceptorBuilder.stateless().backOffOptions(properties.getInitialInterval(),
properties.getMultiplier(), properties.getMaxInterval()).maxAttempts(properties.getMaxAttempts())
ExponentialBackOffPolicy policy = properties.isUseRandomPolicy() ? new ExponentialRandomBackOffPolicy()
: new ExponentialBackOffPolicy();
policy.setInitialInterval(properties.getInitialInterval());
policy.setMultiplier(properties.getMultiplier());
policy.setMaxInterval(properties.getMaxInterval());
return RetryInterceptorBuilder.stateless().backOffPolicy(policy).maxAttempts(properties.getMaxAttempts())
.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright 2013-2024 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.config.client;

import java.lang.reflect.Field;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.retry.backoff.BackOffPolicy;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.backoff.ExponentialRandomBackOffPolicy;
import org.springframework.retry.interceptor.RetryOperationsInterceptor;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.ReflectionUtils;

import static org.assertj.core.api.Assertions.assertThat;

/**
* @author Ryan Baxter
*/
public class ConfigServiceBootstrapConfigurationRetryTest {

private AnnotationConfigApplicationContext context;

@BeforeEach
public void setUp() {
this.context = new AnnotationConfigApplicationContext();
}

@AfterEach
public void tearDown() {
if (this.context != null) {
this.context.close();
}
}

@Test
public void exponentialBackoffPolicy() {
TestPropertyValues.of("spring.cloud.config.enabled=true", "spring.cloud.config.fail-fast=true")
.applyTo(this.context);
this.context.register(ConfigServiceBootstrapConfiguration.class);
this.context.refresh();

RetryOperationsInterceptor retryOperationsInterceptor = this.context.getBean(RetryOperationsInterceptor.class);
Field retryOperationsField = ReflectionUtils.findField(RetryOperationsInterceptor.class, "retryOperations");
retryOperationsField.setAccessible(true);

RetryTemplate retryTemplate = (RetryTemplate) ReflectionUtils.getField(retryOperationsField,
retryOperationsInterceptor);
Field backOffPolicyField = ReflectionUtils.findField(RetryTemplate.class, "backOffPolicy");
backOffPolicyField.setAccessible(true);

BackOffPolicy backOffPolicy = (BackOffPolicy) ReflectionUtils.getField(backOffPolicyField, retryTemplate);
assertThat(backOffPolicy).isNotNull();
assertThat(backOffPolicy).isInstanceOf(ExponentialBackOffPolicy.class);
}

@Test
public void exponentialRandomBackoffPolicy() {
TestPropertyValues.of("spring.cloud.config.enabled=true", "spring.cloud.config.fail-fast=true",
"spring.cloud.config.retry.useRandomPolicy=true").applyTo(this.context);
this.context.register(ConfigServiceBootstrapConfiguration.class);
this.context.refresh();

RetryOperationsInterceptor retryOperationsInterceptor = this.context.getBean(RetryOperationsInterceptor.class);
Field retryOperationsField = ReflectionUtils.findField(RetryOperationsInterceptor.class, "retryOperations");
retryOperationsField.setAccessible(true);

RetryTemplate retryTemplate = (RetryTemplate) ReflectionUtils.getField(retryOperationsField,
retryOperationsInterceptor);
Field backOffPolicyField = ReflectionUtils.findField(RetryTemplate.class, "backOffPolicy");
backOffPolicyField.setAccessible(true);

BackOffPolicy backOffPolicy = (BackOffPolicy) ReflectionUtils.getField(backOffPolicyField, retryTemplate);
assertThat(backOffPolicy).isNotNull();
assertThat(backOffPolicy).isInstanceOf(ExponentialRandomBackOffPolicy.class);
}

}

0 comments on commit 9e64b4c

Please sign in to comment.