Skip to content

Commit 3d7eafe

Browse files
committed
Add warnings for invalid setter values in ExponentialBackoffPolicy
- Add warning logs when setter values don't meet expected constraints - Maintain backward compatibility by not changing behavior Fixes #352 Signed-off-by: kssumin <[email protected]>
1 parent 47a2359 commit 3d7eafe

File tree

2 files changed

+47
-35
lines changed

2 files changed

+47
-35
lines changed

src/main/java/org/springframework/retry/backoff/ExponentialBackOffPolicy.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ protected void cloneValues(ExponentialBackOffPolicy target) {
130130
* @param initialInterval the initial interval
131131
*/
132132
public void setInitialInterval(long initialInterval) {
133+
if (initialInterval < 1) {
134+
logger.warn("Initial interval must be at least 1, but was " + initialInterval);
135+
}
133136
this.initialInterval = initialInterval > 1 ? initialInterval : 1;
134137
}
135138

@@ -139,6 +142,9 @@ public void setInitialInterval(long initialInterval) {
139142
* @param multiplier the multiplier
140143
*/
141144
public void setMultiplier(double multiplier) {
145+
if (multiplier <= 1.0) {
146+
logger.warn("Multiplier must be > 1.0 for effective exponential backoff, but was " + multiplier);
147+
}
142148
this.multiplier = multiplier > 1.0 ? multiplier : 1.0;
143149
}
144150

@@ -150,6 +156,9 @@ public void setMultiplier(double multiplier) {
150156
* @param maxInterval in milliseconds.
151157
*/
152158
public void setMaxInterval(long maxInterval) {
159+
if (maxInterval < 1) {
160+
logger.warn("Max interval must be positive, but was " + maxInterval);
161+
}
153162
this.maxInterval = maxInterval > 0 ? maxInterval : 1;
154163
}
155164

src/test/java/org/springframework/retry/backoff/ExponentialBackOffPolicyTests.java

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
1616

1717
package org.springframework.retry.backoff;
1818

19+
import org.apache.commons.logging.Log;
1920
import org.junit.jupiter.api.Test;
21+
import org.mockito.ArgumentCaptor;
22+
import org.springframework.beans.DirectFieldAccessor;
2023

2124
import static org.assertj.core.api.Assertions.assertThat;
22-
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
25+
import static org.mockito.Mockito.*;
2326

2427
/**
2528
* @author Rob Harrop
@@ -80,49 +83,49 @@ public void testMaximumBackOff() {
8083
}
8184

8285
@Test
83-
public void testMultiBackOff() {
86+
public void testSetMultiplierWithWarning() {
87+
Log logMock = mock(Log.class);
8488
ExponentialBackOffPolicy strategy = new ExponentialBackOffPolicy();
85-
long seed = 40;
86-
double multiplier = 1.2;
87-
strategy.setInitialInterval(seed);
88-
strategy.setMultiplier(multiplier);
89-
strategy.setSleeper(sleeper);
90-
BackOffContext context = strategy.start(null);
91-
for (int x = 0; x < 5; x++) {
92-
strategy.backOff(context);
93-
assertThat(sleeper.getLastBackOff()).isEqualTo(seed);
94-
seed *= multiplier;
95-
}
89+
90+
DirectFieldAccessor accessor = new DirectFieldAccessor(strategy);
91+
accessor.setPropertyValue("logger", logMock);
92+
93+
strategy.setMultiplier(1.0);
94+
95+
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
96+
verify(logMock).warn(captor.capture());
97+
assertThat(captor.getValue())
98+
.isEqualTo("Multiplier must be > 1.0 for effective exponential backoff, but was 1.0");
9699
}
97100

98101
@Test
99-
public void testMultiBackOffWithInitialDelaySupplier() {
102+
public void testSetInitialIntervalWithWarning() {
103+
Log logMock = mock(Log.class);
100104
ExponentialBackOffPolicy strategy = new ExponentialBackOffPolicy();
101-
long seed = 40;
102-
double multiplier = 1.2;
103-
strategy.initialIntervalSupplier(() -> 40L);
104-
strategy.setMultiplier(multiplier);
105-
strategy.setSleeper(sleeper);
106-
BackOffContext context = strategy.start(null);
107-
for (int x = 0; x < 5; x++) {
108-
strategy.backOff(context);
109-
assertThat(sleeper.getLastBackOff()).isEqualTo(seed);
110-
seed *= multiplier;
111-
}
105+
106+
DirectFieldAccessor accessor = new DirectFieldAccessor(strategy);
107+
accessor.setPropertyValue("logger", logMock);
108+
109+
strategy.setInitialInterval(0);
110+
111+
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
112+
verify(logMock).warn(captor.capture());
113+
assertThat(captor.getValue()).isEqualTo("Initial interval must be at least 1, but was 0");
112114
}
113115

114116
@Test
115-
public void testInterruptedStatusIsRestored() {
117+
public void testSetMaxIntervalWithWarning() {
118+
Log logMock = mock(Log.class);
116119
ExponentialBackOffPolicy strategy = new ExponentialBackOffPolicy();
117-
strategy.setSleeper(new Sleeper() {
118-
@Override
119-
public void sleep(long backOffPeriod) throws InterruptedException {
120-
throw new InterruptedException("foo");
121-
}
122-
});
123-
BackOffContext context = strategy.start(null);
124-
assertThatExceptionOfType(BackOffInterruptedException.class).isThrownBy(() -> strategy.backOff(context));
125-
assertThat(Thread.interrupted()).isTrue();
120+
121+
DirectFieldAccessor accessor = new DirectFieldAccessor(strategy);
122+
accessor.setPropertyValue("logger", logMock);
123+
124+
strategy.setMaxInterval(0);
125+
126+
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
127+
verify(logMock).warn(captor.capture());
128+
assertThat(captor.getValue()).isEqualTo("Max interval must be positive, but was 0");
126129
}
127130

128131
}

0 commit comments

Comments
 (0)