diff --git a/src/main/java/com/orbitz/consul/cache/ConsulCache.java b/src/main/java/com/orbitz/consul/cache/ConsulCache.java index d47ded93..637d8c62 100644 --- a/src/main/java/com/orbitz/consul/cache/ConsulCache.java +++ b/src/main/java/com/orbitz/consul/cache/ConsulCache.java @@ -2,6 +2,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.orbitz.consul.ConsulException; import com.orbitz.consul.async.ConsulResponseCallback; @@ -12,8 +13,17 @@ import org.slf4j.LoggerFactory; import java.math.BigInteger; -import java.util.*; -import java.util.concurrent.*; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import static com.google.common.base.Preconditions.checkArgument; @@ -31,6 +41,10 @@ enum State {latent, starting, started, stopped } private final static Logger LOGGER = LoggerFactory.getLogger(ConsulCache.class); + @VisibleForTesting + static final String BACKOFF_DELAY_PROPERTY = "com.orbitz.consul.cache.backOffDelay"; + private static final long BACKOFF_DELAY_QTY_IN_MS = getBackOffDelayInMs(System.getProperties()); + private final AtomicReference latestIndex = new AtomicReference(null); private final AtomicReference> lastResponse = new AtomicReference>(ImmutableMap.of()); private final AtomicReference state = new AtomicReference(State.latent); @@ -45,14 +59,6 @@ enum State {latent, starting, started, stopped } ConsulCache( Function keyConversion, CallbackConsumer callbackConsumer) { - this(keyConversion, callbackConsumer, 10, TimeUnit.SECONDS); - } - - ConsulCache( - Function keyConversion, - CallbackConsumer callbackConsumer, - final long backoffDelayQty, - final TimeUnit backoffDelayUnit) { this.keyConversion = keyConversion; this.callBackConsumer = callbackConsumer; @@ -95,18 +101,35 @@ public void onFailure(Throwable throwable) { if (!isRunning()) { return; } - LOGGER.error(String.format("Error getting response from consul. will retry in %d %s", backoffDelayQty, backoffDelayUnit), throwable); + LOGGER.error(String.format("Error getting response from consul. will retry in %d %s", BACKOFF_DELAY_QTY_IN_MS, TimeUnit.MILLISECONDS), throwable); executorService.schedule(new Runnable() { @Override public void run() { runCallback(); } - }, backoffDelayQty, backoffDelayUnit); + }, BACKOFF_DELAY_QTY_IN_MS, TimeUnit.MILLISECONDS); } }; } + @VisibleForTesting + static long getBackOffDelayInMs(Properties properties) { + String backOffDelay = null; + try { + backOffDelay = properties.getProperty(BACKOFF_DELAY_PROPERTY); + if (!Strings.isNullOrEmpty(backOffDelay)) { + return Long.parseLong(backOffDelay); + } + } catch (Exception ex) { + LOGGER.warn(backOffDelay != null ? + String.format("Error parsing property variable %s: %s", BACKOFF_DELAY_PROPERTY, backOffDelay) : + String.format("Error extracting property variable %s", BACKOFF_DELAY_PROPERTY), + ex); + } + return TimeUnit.SECONDS.toMillis(10); + } + public void start() throws Exception { checkState(state.compareAndSet(State.latent, State.starting),"Cannot transition from state %s to %s", state.get(), State.starting); runCallback(); diff --git a/src/test/java/com/orbitz/consul/cache/ConsulCacheTest.java b/src/test/java/com/orbitz/consul/cache/ConsulCacheTest.java index 4dd4fad2..3dd67302 100644 --- a/src/test/java/com/orbitz/consul/cache/ConsulCacheTest.java +++ b/src/test/java/com/orbitz/consul/cache/ConsulCacheTest.java @@ -14,15 +14,12 @@ import com.orbitz.consul.option.ConsistencyMode; import com.orbitz.consul.option.ImmutableQueryOptions; import com.orbitz.consul.option.QueryOptions; +import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; @@ -260,7 +257,7 @@ public void testLifeCycleDoubleStart() throws Exception { nc.start(); assertEquals(ConsulCache.State.starting, nc.getState()); - if (!nc.awaitInitialized(1, TimeUnit.SECONDS)) { + if (!nc.awaitInitialized(10, TimeUnit.SECONDS)) { fail("cache initialization failed"); } assertEquals(ConsulCache.State.started, nc.getState()); @@ -378,4 +375,24 @@ public void testWatchParamsWithAdditionalIndexAndWaitingThrows() { .build(); ConsulCache.watchParams(index, 10, additionalOptions); } + + @Test + public void testDefaultBackOffDelay() { + Properties properties = new Properties(); + Assert.assertEquals(10000L, ConsulCache.getBackOffDelayInMs(properties)); + } + + @Test + public void testBackOffDelayFromProperties() { + Properties properties = new Properties(); + properties.setProperty(ConsulCache.BACKOFF_DELAY_PROPERTY, "500"); + Assert.assertEquals(500L, ConsulCache.getBackOffDelayInMs(properties)); + } + + @Test + public void testBackOffDelayDoesNotThrow() { + Properties properties = new Properties(); + properties.setProperty(ConsulCache.BACKOFF_DELAY_PROPERTY, "unparseableLong"); + Assert.assertEquals(10000L, ConsulCache.getBackOffDelayInMs(properties)); + } }