diff --git a/build.gradle b/build.gradle index 9030966..d614b32 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ java { } group = 'cloud.eppo' -version = '4.0.1-SNAPSHOT' +version = '5.0.0-SNAPSHOT' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") import org.apache.tools.ant.filters.ReplaceTokens @@ -30,7 +30,7 @@ repositories { } dependencies { - api 'cloud.eppo:sdk-common-jvm:3.6.0' + api 'cloud.eppo:sdk-common-jvm:3.8.0' implementation 'com.github.zafarkhaja:java-semver:0.10.2' implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.2' diff --git a/src/main/java/cloud/eppo/EppoClient.java b/src/main/java/cloud/eppo/EppoClient.java index b16d323..2640925 100644 --- a/src/main/java/cloud/eppo/EppoClient.java +++ b/src/main/java/cloud/eppo/EppoClient.java @@ -5,7 +5,6 @@ import cloud.eppo.cache.LRUInMemoryAssignmentCache; import cloud.eppo.logging.AssignmentLogger; import cloud.eppo.logging.BanditLogger; -import java.util.Timer; import java.util.concurrent.TimeUnit; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -26,7 +25,6 @@ public class EppoClient extends BaseEppoClient { private static final long DEFAULT_JITTER_INTERVAL_RATIO = 10; private static EppoClient instance; - private static Timer pollTimer; public static EppoClient getInstance() { if (instance == null) { @@ -62,13 +60,6 @@ private EppoClient( banditAssignmentCache); } - /** Stops the client from polling Eppo for updated flag and bandit configurations */ - public static void stopPolling() { - if (pollTimer != null) { - pollTimer.cancel(); - } - } - /** Builder pattern to initialize the EppoClient singleton */ public static class Builder { private String apiKey; @@ -163,6 +154,8 @@ public EppoClient buildAndInit() { String sdkVersion = appDetails.getVersion(); if (instance != null) { + // Stop any active polling. + instance.stopPolling(); if (forceReinitialize) { log.warn( "Eppo SDK is already initialized, reinitializing since forceReinitialize is true"); @@ -185,22 +178,13 @@ public EppoClient buildAndInit() { assignmentCache, banditAssignmentCache); - // Stop any active polling - stopPolling(); - - // Set up polling for experiment configurations - pollTimer = new Timer(true); - FetchConfigurationsTask fetchConfigurationsTask = - new FetchConfigurationsTask( - () -> instance.loadConfiguration(), - pollTimer, - pollingIntervalMs, - pollingIntervalMs / DEFAULT_JITTER_INTERVAL_RATIO); - - // Kick off the first fetch - // Graceful mode is implicit here because `FetchConfigurationsTask` catches and logs errors - // without rethrowing. - fetchConfigurationsTask.run(); + // Fetch first configuration + instance.loadConfiguration(); + + // start polling, if enabled. + if (pollingIntervalMs > 0) { + instance.startPolling(pollingIntervalMs, pollingIntervalMs / DEFAULT_JITTER_INTERVAL_RATIO); + } return instance; } diff --git a/src/test/java/cloud/eppo/EppoClientTest.java b/src/test/java/cloud/eppo/EppoClientTest.java index db94f0e..cb971fb 100644 --- a/src/test/java/cloud/eppo/EppoClientTest.java +++ b/src/test/java/cloud/eppo/EppoClientTest.java @@ -11,6 +11,7 @@ import cloud.eppo.api.Attributes; import cloud.eppo.api.BanditActions; import cloud.eppo.api.BanditResult; +import cloud.eppo.api.Configuration; import cloud.eppo.helpers.AssignmentTestCase; import cloud.eppo.helpers.BanditTestCase; import cloud.eppo.helpers.TestUtils; @@ -18,6 +19,7 @@ import cloud.eppo.logging.AssignmentLogger; import cloud.eppo.logging.BanditAssignment; import cloud.eppo.logging.BanditLogger; +import cloud.eppo.ufc.dto.VariationType; import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.junit5.WireMockExtension; @@ -91,7 +93,11 @@ private static String readConfig(String jsonToReturnFilePath) { @AfterEach public void cleanUp() { TestUtils.setBaseClientHttpClientOverrideField(null); - EppoClient.stopPolling(); + try { + EppoClient.getInstance().stopPolling(); + } catch (IllegalStateException ex) { + // pass: Indicates that the singleton Eppo Client has not yet been initialized. + } } @AfterAll @@ -232,7 +238,7 @@ public void testPolling() { // Now, the method should have been called twice verify(httpClientSpy, times(2)).get(anyString()); - EppoClient.stopPolling(); + EppoClient.getInstance().stopPolling(); sleepUninterruptedly(25); // No more calls since stopped @@ -257,6 +263,15 @@ public void testClientMakesDefaultAssignmentsAfterFailingToInitialize() { } } + @Test + public void testGetConfiguration() { + EppoClient eppoClient = initClient(DUMMY_FLAG_API_KEY); + Configuration configuration = eppoClient.getConfiguration(); + assertNotNull(configuration); + assertNotNull(configuration.getFlag("numeric_flag")); + assertEquals(VariationType.NUMERIC, configuration.getFlagType("numeric_flag")); + } + public static void mockHttpError() { // Create a mock instance of EppoHttpClient EppoHttpClient mockHttpClient = mock(EppoHttpClient.class);