mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 16:39:29 +00:00
Avoid divide-by-zero in ExponentialBackOff jitter
When an ExponentialBackOff is configured with an initialInterval of 0 and a positive jitter, the first nextBackOff() evaluated (jitter * (interval / initialInterval)) performs integer division by zero and throws an ArithmeticException. Both initialInterval = 0 and jitter > 0 are individually accepted configurations -- with jitter = 0, an initialInterval of 0 already yields a delay of 0 -- so the combination should not throw. This commit addresses that by guarding the division so that no jitter scaling is applied when initialInterval is 0, leaving the behavior for positive intervals unchanged. Closes gh-36932 Signed-off-by: junhyeong9812 <pickjog@gmail.com>
This commit is contained in:
@@ -311,7 +311,7 @@ public class ExponentialBackOff implements BackOff {
|
||||
long jitter = getJitter();
|
||||
if (jitter > 0) {
|
||||
long initialInterval = getInitialInterval();
|
||||
long applicableJitter = jitter * (interval / initialInterval);
|
||||
long applicableJitter = jitter * (initialInterval > 0 ? (interval / initialInterval) : 1);
|
||||
long min = Math.max(interval - applicableJitter, initialInterval);
|
||||
long max = Math.min(interval + applicableJitter, getMaxInterval());
|
||||
return min + (long) (Math.random() * (max - min));
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.util.backoff.ExponentialBackOff;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
|
||||
/**
|
||||
* Tests for {@link ExponentialBackOff}.
|
||||
@@ -118,6 +119,20 @@ class ExponentialBackOffTests {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> backOff.setMultiplier(0.9));
|
||||
}
|
||||
|
||||
@Test
|
||||
void jitterWithZeroInitialInterval() {
|
||||
// 'initialInterval = 0' and 'jitter > 0' are both individually accepted
|
||||
// configurations, so their combination must not throw. With initialInterval
|
||||
// of 0, the first nextBackOff() previously evaluated 'jitter * (0 / 0)',
|
||||
// resulting in an integer division by zero.
|
||||
ExponentialBackOff backOff = new ExponentialBackOff();
|
||||
backOff.setInitialInterval(0);
|
||||
backOff.setJitter(100);
|
||||
|
||||
BackOffExecution execution = backOff.start();
|
||||
assertThatNoException().isThrownBy(execution::nextBackOff);
|
||||
}
|
||||
|
||||
@Test
|
||||
void maxIntervalReachedImmediately() {
|
||||
ExponentialBackOff backOff = new ExponentialBackOff(1000L, 2.0);
|
||||
|
||||
Reference in New Issue
Block a user