Skip to content

Commit

Permalink
feat!: use sdk-maintained state, require 1.12
Browse files Browse the repository at this point in the history
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
  • Loading branch information
toddbaert committed Sep 23, 2024
1 parent 096d407 commit 9ca7904
Show file tree
Hide file tree
Showing 24 changed files with 544 additions and 877 deletions.
7 changes: 0 additions & 7 deletions hooks/open-telemetry/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,6 @@
</dependencyManagement>

<dependencies>
<dependency>
<groupId>dev.openfeature</groupId>
<artifactId>sdk</artifactId>
<version>[1.4,2.0)</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-semconv</artifactId>
Expand Down
5 changes: 3 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,11 @@
<dependencies>
<dependency>
<!-- provided -->
<!-- this can be overriden in child POMs to support specific SDK requirements -->
<groupId>dev.openfeature</groupId>
<artifactId>sdk</artifactId>
<!-- 1.0 <= v < 2.0 -->
<version>[1.0,2.0)</version>
<!-- 1.12 <= v < 2.0 -->
<version>[1.12,2.0)</version>
<!-- use the version provided at runtime -->
<scope>provided</scope>
</dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ public class ConfigCatProvider extends EventProvider {
@Getter
private ConfigCatClient configCatClient;

@Getter
private ProviderState state = ProviderState.NOT_READY;

private AtomicBoolean isInitialized = new AtomicBoolean(false);

/**
Expand All @@ -64,8 +61,7 @@ public void initialize(EvaluationContext evaluationContext) throws Exception {
configCatClient = ConfigCatClient.get(configCatProviderConfig.getSdkKey(),
configCatProviderConfig.getOptions());
configCatProviderConfig.postInit();
state = ProviderState.READY;
log.info("finished initializing provider, state: {}", state);
log.info("finished initializing provider");

configCatClient.getHooks().addOnClientReady(() -> {
ProviderEventDetails providerEventDetails = ProviderEventDetails.builder()
Expand Down Expand Up @@ -123,12 +119,6 @@ public ProviderEvaluation<Value> getObjectEvaluation(String key, Value defaultVa

private <T> ProviderEvaluation<T> getEvaluation(Class<T> classOfT, String key, T defaultValue,
EvaluationContext ctx) {
if (!ProviderState.READY.equals(state)) {
if (ProviderState.NOT_READY.equals(state)) {
throw new ProviderNotReadyError(PROVIDER_NOT_YET_INITIALIZED);
}
throw new GeneralError(UNKNOWN_ERROR);
}
User user = ctx == null ? null : ContextTransformer.transform(ctx);
EvaluationDetails<T> evaluationDetails;
T evaluatedValue;
Expand Down Expand Up @@ -157,6 +147,5 @@ public void shutdown() {
if (configCatClient != null) {
configCatClient.close();
}
state = ProviderState.NOT_READY;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,27 +181,6 @@ void getStringEvaluationByUser() {
assertEquals("fallback", client.getStringValue(USERS_FLAG_NAME + "Str", "111", evaluationContext));
}

@SneakyThrows
@Test
void shouldThrowIfNotInitialized() {
ConfigCatProviderConfig configCatProviderConfig = ConfigCatProviderConfig.builder().sdkKey("configcat-sdk-1/TEST_KEY-0123456789012/1234567890123456789012").build();
ConfigCatProvider tempConfigCatProvider = new ConfigCatProvider(configCatProviderConfig);

assertThrows(ProviderNotReadyError.class, ()-> tempConfigCatProvider.getBooleanEvaluation("fail_not_initialized", false, new ImmutableContext()));

OpenFeatureAPI.getInstance().setProviderAndWait("tempConfigCatProvider", tempConfigCatProvider);

assertThrows(GeneralError.class, ()-> tempConfigCatProvider.initialize(null));

tempConfigCatProvider.shutdown();

assertThrows(ProviderNotReadyError.class, ()-> tempConfigCatProvider.getBooleanEvaluation("fail_not_initialized", false, new ImmutableContext()));
assertThrows(ProviderNotReadyError.class, ()-> tempConfigCatProvider.getDoubleEvaluation("fail_not_initialized", 0.1, new ImmutableContext()));
assertThrows(ProviderNotReadyError.class, ()-> tempConfigCatProvider.getIntegerEvaluation("fail_not_initialized", 3, new ImmutableContext()));
assertThrows(ProviderNotReadyError.class, ()-> tempConfigCatProvider.getObjectEvaluation("fail_not_initialized", null, new ImmutableContext()));
assertThrows(ProviderNotReadyError.class, ()-> tempConfigCatProvider.getStringEvaluation("fail_not_initialized", "", new ImmutableContext()));
}

@Test
void eventsTest() {
configCatProvider.emitProviderReady(ProviderEventDetails.builder().build());
Expand Down
9 changes: 0 additions & 9 deletions providers/flagd/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,7 @@
</developers>

<dependencies>

<!-- we inherent dev.openfeature.javasdk and the test dependencies from the parent pom -->
<!-- override parent definition -->
<dependency>
<groupId>dev.openfeature</groupId>
<artifactId>sdk</artifactId>
<version>[1.4,2.0)</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@
@SuppressWarnings({"PMD.TooManyStaticImports", "checkstyle:NoFinalizer"})
public class FlagdProvider extends EventProvider {
private static final String FLAGD_PROVIDER = "flagD Provider";

private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Resolver flagResolver;
private ProviderState state = ProviderState.NOT_READY;
private boolean initialized = false;
private volatile boolean initialized = false;
private volatile boolean connected = false;

private EvaluationContext evaluationContext;

Expand All @@ -52,14 +50,14 @@ public FlagdProvider() {
public FlagdProvider(final FlagdOptions options) {
switch (options.getResolverType().asString()) {
case Config.RESOLVER_IN_PROCESS:
this.flagResolver = new InProcessResolver(options, this::setState);
this.flagResolver = new InProcessResolver(options, this::isConnected, this::onResolverConnectionChanged);
break;
case Config.RESOLVER_RPC:
this.flagResolver =
new GrpcResolver(options,
new Cache(options.getCacheType(), options.getMaxCacheSize()),
this::getState,
this::setState);
this::isConnected,
this::onResolverConnectionChanged);
break;
default:
throw new IllegalStateException(
Expand All @@ -86,24 +84,13 @@ public synchronized void shutdown() {

try {
this.flagResolver.shutdown();
this.initialized = false;
} catch (Exception e) {
log.error("Error during shutdown {}", FLAGD_PROVIDER, e);
}
}

@Override
public ProviderState getState() {
Lock l = this.lock.readLock();
try {
l.lock();
return this.state;
} finally {
l.unlock();
this.initialized = false;
}
}


@Override
public Metadata getMetadata() {
return () -> FLAGD_PROVIDER;
Expand Down Expand Up @@ -142,49 +129,32 @@ private EvaluationContext mergeContext(final EvaluationContext clientCallCtx) {
return clientCallCtx;
}

private void setState(ProviderState newState, List<String> changedFlagsKeys) {
ProviderState oldState;
Lock l = this.lock.writeLock();
try {
l.lock();
oldState = this.state;
this.state = newState;
} finally {
l.unlock();
}
this.handleStateTransition(oldState, newState, changedFlagsKeys);
private boolean isConnected() {
return this.connected;
}

private void handleStateTransition(ProviderState oldState, ProviderState newState, List<String> changedFlagKeys) {
// we got initialized
if (ProviderState.NOT_READY.equals(oldState) && ProviderState.READY.equals(newState)) {
// nothing to do, the SDK emits the events
log.debug("Init completed");
return;
}
// we got shutdown, not checking oldState as behavior remains the same for shutdown
if (ProviderState.NOT_READY.equals(newState)) {
// nothing to do
log.debug("shutdown completed");
return;
}
private void onResolverConnectionChanged(boolean newConnectedState, List<String> changedFlagKeys) {
boolean previous = connected;
boolean current = newConnectedState;
this.connected = newConnectedState;

// configuration changed
if (ProviderState.READY.equals(oldState) && ProviderState.READY.equals(newState)) {
if (initialized && previous && current) {
log.debug("Configuration changed");
ProviderEventDetails details = ProviderEventDetails.builder().flagsChanged(changedFlagKeys)
.message("configuration changed").build();
this.emitProviderConfigurationChanged(details);
return;
}
// there was an error
if (ProviderState.READY.equals(oldState) && ProviderState.ERROR.equals(newState)) {
if (initialized && previous && !current) {
log.debug("There has been an error");
ProviderEventDetails details = ProviderEventDetails.builder().message("there has been an error").build();
this.emitProviderError(details);
return;
}
// we recover from an error
if (ProviderState.ERROR.equals(oldState) && ProviderState.READY.equals(newState)) {
// we recovered from an error
if (initialized && !previous && current) {
log.debug("Recovered from error");
ProviderEventDetails details = ProviderEventDetails.builder().message("recovered from error").build();
this.emitProviderReady(details);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.openfeature.contrib.providers.flagd.resolver.common;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;

import dev.openfeature.sdk.exceptions.GeneralError;

Expand All @@ -14,11 +15,11 @@ private Util() {

/**
* A helper to block the caller for given conditions.
*
* @param deadline number of milliseconds to block
* @param check {@link AtomicBoolean} to check for status true
* @param connectedSupplier func to check for status true
* @throws InterruptedException
*/
public static void busyWaitAndCheck(final Long deadline, final AtomicBoolean check) throws InterruptedException {
public static void busyWaitAndCheck(final Long deadline, final Supplier<Boolean> connectedSupplier) throws InterruptedException {
long start = System.currentTimeMillis();

do {
Expand All @@ -28,6 +29,6 @@ public static void busyWaitAndCheck(final Long deadline, final AtomicBoolean che
}

Thread.sleep(50L);
} while (!check.get());
} while (!connectedSupplier.get());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
@Slf4j
@SuppressFBWarnings(justification = "cache needs to be read and write by multiple objects")
class EventStreamObserver implements StreamObserver<EventStreamResponse> {
private final BiConsumer<ProviderState, List<String>> stateConsumer;
private final BiConsumer<Boolean, List<String>> stateConsumer;
private final Object sync;
private final Cache cache;

Expand All @@ -35,7 +35,7 @@ class EventStreamObserver implements StreamObserver<EventStreamResponse> {
* @param cache cache to update
* @param stateConsumer lambda to call for setting the state
*/
EventStreamObserver(Object sync, Cache cache, BiConsumer<ProviderState, List<String>> stateConsumer) {
EventStreamObserver(Object sync, Cache cache, BiConsumer<Boolean, List<String>> stateConsumer) {
this.sync = sync;
this.cache = cache;
this.stateConsumer = stateConsumer;
Expand All @@ -61,7 +61,7 @@ public void onError(Throwable t) {
if (this.cache.getEnabled()) {
this.cache.clear();
}
this.stateConsumer.accept(ProviderState.ERROR, Collections.emptyList());
this.stateConsumer.accept(false, Collections.emptyList());

// handle last call of this stream
handleEndOfStream();
Expand All @@ -72,7 +72,7 @@ public void onCompleted() {
if (this.cache.getEnabled()) {
this.cache.clear();
}
this.stateConsumer.accept(ProviderState.ERROR, Collections.emptyList());
this.stateConsumer.accept(false, Collections.emptyList());

// handle last call of this stream
handleEndOfStream();
Expand All @@ -99,11 +99,11 @@ private void handleConfigurationChangeEvent(EventStreamResponse value) {
}
}

this.stateConsumer.accept(ProviderState.READY, changedFlags);
this.stateConsumer.accept(true, changedFlags);
}

private void handleProviderReadyEvent() {
this.stateConsumer.accept(ProviderState.READY, Collections.emptyList());
this.stateConsumer.accept(true, Collections.emptyList());
if (this.cache.getEnabled()) {
this.cache.clear();
}
Expand Down
Loading

0 comments on commit 9ca7904

Please sign in to comment.