diff --git a/src/main/java/software/amazon/cloudformation/proxy/delay/CappedExponential.java b/src/main/java/software/amazon/cloudformation/proxy/delay/CappedExponential.java index 94ada0a7..603616e0 100644 --- a/src/main/java/software/amazon/cloudformation/proxy/delay/CappedExponential.java +++ b/src/main/java/software/amazon/cloudformation/proxy/delay/CappedExponential.java @@ -23,8 +23,6 @@ public class CappedExponential extends MinDelayAbstractBase { final Duration maxDelay; - private Duration accrued = Duration.ZERO; - CappedExponential(Duration timeout, Duration minDelay, Double powerBy, @@ -68,19 +66,27 @@ public CappedExponential build() { } } + /** + * Calculating accrued time as summation of all the delay based on attempt. + * Assumption:- attempt will not be big number. + */ @Override public Duration nextDelay(int attempt) { Duration next = Duration.ofSeconds(Math.round(Math.pow(powerBy, attempt))); Duration nextDelay = Duration.ofSeconds(Math.min(maxDelay.getSeconds(), next.getSeconds())); + Duration accrued = Duration.ZERO; + for (int i = 1; i <= attempt; i++) { + Duration nextDuration = i > 1 ? nextDelay(i - 1) : Duration.ZERO; + accrued = accrued.plus(nextDuration); + } accrued = accrued.plus(nextDelay); return enforceBounds(accrued, nextDelay); - } @Override public String toString() { - return "CappedExponential{" + "powerBy=" + powerBy + ", maxDelay=" + maxDelay + ", accrued=" + accrued + ", minDelay=" - + minDelay + ", timeout=" + timeout + '}'; + return "CappedExponential{" + "powerBy=" + powerBy + ", maxDelay=" + maxDelay + ", minDelay=" + minDelay + ", timeout=" + + timeout + '}'; } } diff --git a/src/test/java/software/amazon/cloudformation/proxy/DelayTest.java b/src/test/java/software/amazon/cloudformation/proxy/DelayTest.java index e52e6252..0a1711c9 100644 --- a/src/test/java/software/amazon/cloudformation/proxy/DelayTest.java +++ b/src/test/java/software/amazon/cloudformation/proxy/DelayTest.java @@ -206,7 +206,7 @@ public void cappedExponentialDelays() { final Delay cappedExponential = CappedExponential.of().timeout(Duration.ofMinutes(20)).maxDelay(MAX_DELAY).powerBy(1.3) .minDelay(Duration.ofSeconds(1)).build(); int[] results = { 1, 1, 2, 2, 3, 4, 5, 6, 8, 11, 14, 15, 15, 15, 15, 15, 15 }; - for (int tries = 0; tries <= 15; tries++) { + for (int tries = 1; tries <= 15; tries++) { Duration delay = cappedExponential.nextDelay(tries); assertThat(results[tries]).isEqualTo((int) delay.getSeconds()); if (tries >= 11) { @@ -218,7 +218,7 @@ public void cappedExponentialDelays() { final Delay cappedExponentialNoPower = CappedExponential.of().timeout(Duration.ofMinutes(20)).maxDelay(MAX_DELAY) .minDelay(Duration.ofSeconds(2)).build(); int[] resultsNoPower = { 2, 2, 4, 8, 15, 15, 15, 15, 15 }; - for (int tries = 0; tries <= 6; tries++) { + for (int tries = 1; tries <= 6; tries++) { Duration delay = cappedExponentialNoPower.nextDelay(tries); assertThat(resultsNoPower[tries]).isEqualTo((int) delay.getSeconds()); if (tries >= 5) { @@ -230,11 +230,11 @@ public void cappedExponentialDelays() { final Delay cappedExponentialTimeout = CappedExponential.of().timeout(Duration.ofSeconds(5)) .maxDelay(Duration.ofSeconds(1)).powerBy(1.0).minDelay(Duration.ofSeconds(1)).build(); - int[] resultsTimeout = { 1, 1, 1, 1, 1, 0 }; - for (int tries = 0; tries <= 5; tries++) { + int[] resultsTimeout = { 1, 1, 1, 1, 1, 1, 0 }; + for (int tries = 1; tries <= 6; tries++) { Duration delay = cappedExponentialTimeout.nextDelay(tries); assertThat(resultsTimeout[tries]).isEqualTo((int) delay.getSeconds()); - if (tries >= 5) { + if (tries >= 6) { assertThat(0).isEqualTo(delay.getSeconds()); } } @@ -242,8 +242,8 @@ public void cappedExponentialDelays() { // If minDelay is not passed, it's set to default 1. final Delay cappedExponentialNoMinDelay = CappedExponential.of().timeout(Duration.ofSeconds(5)) .maxDelay(Duration.ofSeconds(1)).powerBy(1.0).build(); - int[] resultsNoMinDelay = { 1, 1, 1, 1, 1, 0 }; - for (int tries = 0; tries <= 5; tries++) { + int[] resultsNoMinDelay = { 1, 1, 1, 1, 1, 1, 0 }; + for (int tries = 1; tries <= 5; tries++) { Duration delay = cappedExponentialNoMinDelay.nextDelay(tries); assertThat(resultsNoMinDelay[tries]).isEqualTo((int) delay.getSeconds()); } @@ -252,18 +252,18 @@ public void cappedExponentialDelays() { final Delay cappedExponentialNoMaxDelay = CappedExponential.of().timeout(Duration.ofMinutes(20)) .minDelay(Duration.ofSeconds(2)).build(); int[] resultsNoMaxDelay = { 2, 2, 4, 8, 16, 20, 20, 20, 20 }; - for (int tries = 0; tries <= 6; tries++) { + for (int tries = 1; tries <= 6; tries++) { Duration delay = cappedExponentialNoMaxDelay.nextDelay(tries); assertThat(resultsNoMaxDelay[tries]).isEqualTo((int) delay.getSeconds()); } final Delay cappedExponentialSameMinMaxDelay = CappedExponential.of().timeout(Duration.ofSeconds(5)) .maxDelay(Duration.ofSeconds(1)).powerBy(1.3).minDelay(Duration.ofSeconds(1)).build(); - int[] resultsSameMinMaxDelay = { 1, 1, 1, 1, 1, 0 }; - for (int tries = 0; tries <= 5; tries++) { + int[] resultsSameMinMaxDelay = { 1, 1, 1, 1, 1, 1, 0 }; + for (int tries = 1; tries <= 6; tries++) { Duration delay = cappedExponentialSameMinMaxDelay.nextDelay(tries); assertThat(resultsSameMinMaxDelay[tries]).isEqualTo((int) delay.getSeconds()); - if (tries >= 5) { + if (tries >= 6) { assertThat(0).isEqualTo(delay.getSeconds()); } }