Skip to content

Commit

Permalink
Fix binary backoff calculation for error transition delay.
Browse files Browse the repository at this point in the history
  • Loading branch information
jsyrjala committed Oct 31, 2014
1 parent aa1e2be commit 7a77967
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.nitorcreations.nflow.engine.workflow.definition;

import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.MINUTES;
Expand All @@ -9,6 +10,8 @@
import org.joda.time.DateTime;
import org.springframework.core.env.Environment;

import java.math.BigInteger;

/**
* Configuration for the workflow execution.
*/
Expand Down Expand Up @@ -144,7 +147,7 @@ public WorkflowSettings build() {
* @return Next activation time.
*/
public DateTime getErrorTransitionActivation(int retryCount) {
return now().plusMillis(calculateBinaryBackoffDelay(retryCount + 1, minErrorTransitionDelay, maxErrorTransitionDelay));
return now().plus(calculateBinaryBackoffDelay(retryCount + 1, minErrorTransitionDelay, maxErrorTransitionDelay));
}

/**
Expand All @@ -158,8 +161,14 @@ public DateTime getErrorTransitionActivation(int retryCount) {
* Maximum retry delay.
* @return Delay in milliseconds.
*/
protected int calculateBinaryBackoffDelay(int retryCount, int minDelay, int maxDelay) {
return min(minDelay * (1 << retryCount), maxDelay);
protected long calculateBinaryBackoffDelay(int retryCount, long minDelay, long maxDelay) {
BigInteger delay = BigInteger.valueOf(minDelay).multiply(BigInteger.valueOf(2).pow(retryCount));
if(!BigInteger.valueOf(delay.longValue()).equals(delay)) {
// got overflow in delay calculation
// Java 1.8 has delay.longValueExact()
return maxDelay;
}
return max(minDelay, min(delay.longValue(), maxDelay));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,47 @@
import static org.joda.time.DateTimeUtils.currentTimeMillis;
import static org.junit.Assert.assertThat;

import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public class WorkflowSettingsTest {
DateTime now = new DateTime(2014, 10, 22, 20, 44, 0);

@Before
public void setup() {
DateTimeUtils.setCurrentMillisFixed(now.getMillis());
}

@After
public void teardown() {
DateTimeUtils.setCurrentMillisSystem();
}

@Test
public void verifyConsantDefaultValues() {
public void verifyConstantDefaultValues() {
WorkflowSettings s = new WorkflowSettings.Builder().build();
assertThat(s.immediateTransitionDelay, is(0));
assertThat(s.shortTransitionDelay, is(30000));
long delta = s.getShortTransitionActivation().getMillis() - currentTimeMillis() - 30000;
assertThat(delta, greaterThanOrEqualTo(-1000L));
assertThat(delta, lessThanOrEqualTo(0L));
}

@Test
public void errorTransitionDelayIsBetweenMinAndMaxDelay() {
int maxDelay = 1_000_000;
int minDelay = 1000;
WorkflowSettings s = new WorkflowSettings.Builder().setMinErrorTransitionDelay(minDelay).setMaxErrorTransitionDelay(maxDelay).build();
long prevDelay = 0;
for(int retryCount = 0 ; retryCount < 100 ; retryCount++) {
long delay = s.getErrorTransitionActivation(retryCount).getMillis() - now.getMillis();
assertThat(delay, greaterThanOrEqualTo((long)minDelay));
assertThat(delay, lessThanOrEqualTo((long)maxDelay));
assertThat(delay, greaterThanOrEqualTo(prevDelay));
prevDelay = delay;
}
}
}

0 comments on commit 7a77967

Please sign in to comment.