Skip to content

Commit 5b032dc

Browse files
committed
Merge remote-tracking branch 'upstream/main' into feat/add_new_provider_type
Signed-off-by: Simon Schrottner <[email protected]>
2 parents fd0dfeb + 23c5e69 commit 5b032dc

File tree

15 files changed

+187
-79
lines changed

15 files changed

+187
-79
lines changed

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"providers/flagd": "0.10.5",
33
"hooks/open-telemetry": "3.2.1",
4-
"providers/go-feature-flag": "0.4.0",
4+
"providers/go-feature-flag": "0.4.1",
55
"providers/flagsmith": "0.0.9",
66
"providers/env-var": "0.0.7",
77
"providers/jsonlogic-eval-provider": "1.1.1",

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,14 @@
104104
<dependency>
105105
<groupId>net.bytebuddy</groupId>
106106
<artifactId>byte-buddy</artifactId>
107-
<version>1.15.11</version>
107+
<version>1.16.1</version>
108108
<scope>test</scope>
109109
</dependency>
110110

111111
<dependency>
112112
<groupId>net.bytebuddy</groupId>
113113
<artifactId>byte-buddy-agent</artifactId>
114-
<version>1.15.11</version>
114+
<version>1.16.1</version>
115115
<scope>test</scope>
116116
</dependency>
117117
<!-- End mockito workaround-->
@@ -126,7 +126,7 @@
126126
<dependency>
127127
<groupId>org.assertj</groupId>
128128
<artifactId>assertj-core</artifactId>
129-
<version>3.27.2</version>
129+
<version>3.27.3</version>
130130
<scope>test</scope>
131131
</dependency>
132132

providers/flagd/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<properties>
1616
<!-- exclusion expression for e2e tests -->
1717
<testExclusions>**/e2e/*.java</testExclusions>
18-
<io.grpc.version>1.69.0</io.grpc.version>
18+
<io.grpc.version>1.69.1</io.grpc.version>
1919
<!-- caution - updating this will break compatibility with older protobuf-java versions -->
2020
<protobuf-java.min.version>3.25.5</protobuf-java.min.version>
2121
</properties>
@@ -122,7 +122,7 @@
122122
<dependency>
123123
<groupId>org.semver4j</groupId>
124124
<artifactId>semver4j</artifactId>
125-
<version>5.5.0</version>
125+
<version>5.6.0</version>
126126
</dependency>
127127

128128
<dependency>

providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/FlagdProvider.java

Lines changed: 77 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,12 @@ public class FlagdProvider extends EventProvider {
3636
private Function<Structure, EvaluationContext> contextEnricher;
3737
private static final String FLAGD_PROVIDER = "flagd";
3838
private final Resolver flagResolver;
39-
private volatile boolean initialized = false;
40-
private volatile Structure syncMetadata = new ImmutableStructure();
41-
private volatile EvaluationContext enrichedContext = new ImmutableContext();
4239
private final List<Hook> hooks = new ArrayList<>();
43-
private volatile ProviderEvent previousEvent = null;
44-
private final Object eventLock;
40+
private final EventsLock eventsLock = new EventsLock();
4541

4642
/**
47-
* An executor service responsible for emitting {@link ProviderEvent#PROVIDER_ERROR} after the provider went
43+
* An executor service responsible for emitting
44+
* {@link ProviderEvent#PROVIDER_ERROR} after the provider went
4845
* {@link ProviderEvent#PROVIDER_STALE} for {@link #gracePeriod} seconds.
4946
*/
5047
private final ScheduledExecutorService errorExecutor;
@@ -55,7 +52,8 @@ public class FlagdProvider extends EventProvider {
5552
private ScheduledFuture<?> errorTask;
5653

5754
/**
58-
* The grace period in milliseconds to wait after {@link ProviderEvent#PROVIDER_STALE} before emitting a
55+
* The grace period in milliseconds to wait after
56+
* {@link ProviderEvent#PROVIDER_STALE} before emitting a
5957
* {@link ProviderEvent#PROVIDER_ERROR}.
6058
*/
6159
private final long gracePeriod;
@@ -96,10 +94,22 @@ public FlagdProvider(final FlagdOptions options) {
9694
}
9795
hooks.add(new SyncMetadataHook(this::getEnrichedContext));
9896
contextEnricher = options.getContextEnricher();
99-
this.errorExecutor = Executors.newSingleThreadScheduledExecutor();
100-
this.gracePeriod = options.getRetryGracePeriod();
101-
this.deadline = options.getDeadline();
102-
this.eventLock = new Object();
97+
errorExecutor = Executors.newSingleThreadScheduledExecutor();
98+
gracePeriod = options.getRetryGracePeriod();
99+
deadline = options.getDeadline();
100+
}
101+
102+
/**
103+
* Internal constructor for test cases.
104+
* DO NOT MAKE PUBLIC
105+
*/
106+
FlagdProvider(Resolver resolver, boolean initialized) {
107+
this.flagResolver = resolver;
108+
deadline = Config.DEFAULT_DEADLINE;
109+
gracePeriod = Config.DEFAULT_STREAM_RETRY_GRACE_PERIOD;
110+
hooks.add(new SyncMetadataHook(this::getEnrichedContext));
111+
errorExecutor = Executors.newSingleThreadScheduledExecutor();
112+
this.eventsLock.initialized = initialized;
103113
}
104114

105115
@Override
@@ -108,21 +118,26 @@ public List<Hook> getProviderHooks() {
108118
}
109119

110120
@Override
111-
public synchronized void initialize(EvaluationContext evaluationContext) throws Exception {
112-
if (this.initialized) {
113-
return;
114-
}
121+
public void initialize(EvaluationContext evaluationContext) throws Exception {
122+
synchronized (eventsLock) {
123+
if (eventsLock.initialized) {
124+
return;
125+
}
115126

116-
this.flagResolver.init();
117-
// block till ready - this works with deadline fine for rpc, but with in_process we also need to take parsing
118-
// into the equation
119-
// TODO: evaluate where we are losing time, so we can remove this magic number - follow up
120-
Util.busyWaitAndCheck(this.deadline + 200, () -> initialized);
127+
flagResolver.init();
128+
}
129+
// block till ready - this works with deadline fine for rpc, but with in_process
130+
// we also need to take parsing into the equation
131+
// TODO: evaluate where we are losing time, so we can remove this magic number -
132+
// follow up
133+
// wait outside of the synchonrization or we'll deadlock
134+
Util.busyWaitAndCheck(this.deadline * 2, () -> eventsLock.initialized);
121135
}
122136

123137
@Override
124-
public synchronized void shutdown() {
125-
if (!this.initialized) {
138+
public void shutdown() {
139+
synchronized (eventsLock) {
140+
if (!eventsLock.initialized) {
126141
return;
127142
}
128143
try {
@@ -131,10 +146,11 @@ public synchronized void shutdown() {
131146
errorExecutor.shutdownNow();
132147
errorExecutor.awaitTermination(deadline, TimeUnit.MILLISECONDS);
133148
}
134-
} catch (Exception e) {
135-
log.error("Error during shutdown {}", FLAGD_PROVIDER, e);
136-
} finally {
137-
this.initialized = false;
149+
} catch (Exception e) {
150+
log.error("Error during shutdown {}", FLAGD_PROVIDER, e);
151+
} finally {
152+
eventsLock.initialized = false;
153+
}
138154
}
139155
}
140156

@@ -145,27 +161,27 @@ public Metadata getMetadata() {
145161

146162
@Override
147163
public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defaultValue, EvaluationContext ctx) {
148-
return this.flagResolver.booleanEvaluation(key, defaultValue, ctx);
164+
return flagResolver.booleanEvaluation(key, defaultValue, ctx);
149165
}
150166

151167
@Override
152168
public ProviderEvaluation<String> getStringEvaluation(String key, String defaultValue, EvaluationContext ctx) {
153-
return this.flagResolver.stringEvaluation(key, defaultValue, ctx);
169+
return flagResolver.stringEvaluation(key, defaultValue, ctx);
154170
}
155171

156172
@Override
157173
public ProviderEvaluation<Double> getDoubleEvaluation(String key, Double defaultValue, EvaluationContext ctx) {
158-
return this.flagResolver.doubleEvaluation(key, defaultValue, ctx);
174+
return flagResolver.doubleEvaluation(key, defaultValue, ctx);
159175
}
160176

161177
@Override
162178
public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext ctx) {
163-
return this.flagResolver.integerEvaluation(key, defaultValue, ctx);
179+
return flagResolver.integerEvaluation(key, defaultValue, ctx);
164180
}
165181

166182
@Override
167183
public ProviderEvaluation<Value> getObjectEvaluation(String key, Value defaultValue, EvaluationContext ctx) {
168-
return this.flagResolver.objectEvaluation(key, defaultValue, ctx);
184+
return flagResolver.objectEvaluation(key, defaultValue, ctx);
169185
}
170186

171187
/**
@@ -178,7 +194,7 @@ public ProviderEvaluation<Value> getObjectEvaluation(String key, Value defaultVa
178194
* @return Object map representing sync metadata
179195
*/
180196
protected Structure getSyncMetadata() {
181-
return new ImmutableStructure(syncMetadata.asMap());
197+
return new ImmutableStructure(eventsLock.syncMetadata.asMap());
182198
}
183199

184200
/**
@@ -187,42 +203,45 @@ protected Structure getSyncMetadata() {
187203
* @return context
188204
*/
189205
EvaluationContext getEnrichedContext() {
190-
return enrichedContext;
206+
return eventsLock.enrichedContext;
191207
}
192208

193209
@SuppressWarnings("checkstyle:fallthrough")
194210
private void onProviderEvent(FlagdProviderEvent flagdProviderEvent) {
195211

196-
synchronized (eventLock) {
212+
synchronized (eventsLock) {
197213
log.info("FlagdProviderEvent: {}", flagdProviderEvent);
198-
syncMetadata = flagdProviderEvent.getSyncMetadata();
214+
eventsLock.syncMetadata = flagdProviderEvent.getSyncMetadata();
199215
if (flagdProviderEvent.getSyncMetadata() != null) {
200-
enrichedContext = contextEnricher.apply(flagdProviderEvent.getSyncMetadata());
216+
eventsLock.enrichedContext = contextEnricher.apply(flagdProviderEvent.getSyncMetadata());
201217
}
202218

203219
/*
204-
We only use Error and Ready as previous states.
205-
As error will first be emitted as Stale, and only turns after a while into an emitted Error.
206-
Ready is needed, as the InProcessResolver does not have a dedicated ready event, hence we need to
207-
forward a configuration changed to the ready, if we are not in the ready state.
220+
* We only use Error and Ready as previous states.
221+
* As error will first be emitted as Stale, and only turns after a while into an
222+
* emitted Error.
223+
* Ready is needed, as the InProcessResolver does not have a dedicated ready
224+
* event, hence we need to
225+
* forward a configuration changed to the ready, if we are not in the ready
226+
* state.
208227
*/
209228
switch (flagdProviderEvent.getEvent()) {
210229
case PROVIDER_CONFIGURATION_CHANGED:
211-
if (previousEvent == ProviderEvent.PROVIDER_READY) {
230+
if (eventsLock.previousEvent == ProviderEvent.PROVIDER_READY) {
212231
onConfigurationChanged(flagdProviderEvent);
213232
break;
214233
}
215234
// intentional fall through, a not-ready change will trigger a ready.
216235
case PROVIDER_READY:
217236
onReady();
218-
previousEvent = ProviderEvent.PROVIDER_READY;
237+
eventsLock.previousEvent = ProviderEvent.PROVIDER_READY;
219238
break;
220239

221240
case PROVIDER_ERROR:
222-
if (previousEvent != ProviderEvent.PROVIDER_ERROR) {
241+
if (eventsLock.previousEvent != ProviderEvent.PROVIDER_ERROR) {
223242
onError();
224243
}
225-
previousEvent = ProviderEvent.PROVIDER_ERROR;
244+
eventsLock.previousEvent = ProviderEvent.PROVIDER_ERROR;
226245
break;
227246
default:
228247
log.info("Unknown event {}", flagdProviderEvent.getEvent());
@@ -238,8 +257,8 @@ private void onConfigurationChanged(FlagdProviderEvent flagdProviderEvent) {
238257
}
239258

240259
private void onReady() {
241-
if (!initialized) {
242-
initialized = true;
260+
if (!eventsLock.initialized) {
261+
eventsLock.initialized = true;
243262
log.info("initialized FlagdProvider");
244263
}
245264
if (errorTask != null && !errorTask.isCancelled()) {
@@ -264,7 +283,7 @@ private void onError() {
264283
if (!errorExecutor.isShutdown()) {
265284
errorTask = errorExecutor.schedule(
266285
() -> {
267-
if (previousEvent == ProviderEvent.PROVIDER_ERROR) {
286+
if (eventsLock.previousEvent == ProviderEvent.PROVIDER_ERROR) {
268287
log.debug(
269288
"Provider did not reconnect successfully within {}s. Emit ERROR event...",
270289
gracePeriod);
@@ -278,4 +297,15 @@ private void onError() {
278297
TimeUnit.SECONDS);
279298
}
280299
}
300+
301+
/**
302+
* Contains all fields we need to worry about locking, used as intrinsic lock
303+
* for sync blocks.
304+
*/
305+
static class EventsLock {
306+
volatile ProviderEvent previousEvent = null;
307+
volatile Structure syncMetadata = new ImmutableStructure();
308+
volatile boolean initialized = false;
309+
volatile EvaluationContext enrichedContext = new ImmutableContext();
310+
}
281311
}

providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/FlagdOptionsTest.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ void TestBuilderOptions() {
6060
.certPath("etc/cert/ca.crt")
6161
.cacheType("lru")
6262
.maxCacheSize(100)
63-
.resolverType(Resolver.RPC)
63+
.resolverType(Resolver.IN_PROCESS)
6464
.targetUri("dns:///localhost:8016")
6565
.customConnector(connector)
6666
.keepAlive(1000)
@@ -72,8 +72,6 @@ void TestBuilderOptions() {
7272
assertEquals("etc/cert/ca.crt", flagdOptions.getCertPath());
7373
assertEquals("lru", flagdOptions.getCacheType());
7474
assertEquals(100, flagdOptions.getMaxCacheSize());
75-
assertEquals("app=weatherApp", flagdOptions.getSelector());
76-
assertEquals(openTelemetry, flagdOptions.getOpenTelemetry());
7775
assertEquals(connector, flagdOptions.getCustomConnector());
7876
assertEquals(Resolver.IN_PROCESS, flagdOptions.getResolverType());
7977
assertEquals("dns:///localhost:8016", flagdOptions.getTargetUri());

providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/FlagdProviderTest.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -700,24 +700,14 @@ private FlagdProvider createProvider(GrpcConnector grpc, Cache cache) {
700700
final FlagdOptions flagdOptions = FlagdOptions.builder().build();
701701
final GrpcResolver grpcResolver = new GrpcResolver(flagdOptions, cache, (connectionEvent) -> {});
702702

703-
final FlagdProvider provider = new FlagdProvider();
704-
705703
try {
706704
Field connector = GrpcResolver.class.getDeclaredField("connector");
707705
connector.setAccessible(true);
708706
connector.set(grpcResolver, grpc);
709-
710-
Field flagResolver = FlagdProvider.class.getDeclaredField("flagResolver");
711-
flagResolver.setAccessible(true);
712-
flagResolver.set(provider, grpcResolver);
713-
714-
Field initialized = FlagdProvider.class.getDeclaredField("initialized");
715-
initialized.setAccessible(true);
716-
initialized.set(provider, true);
717707
} catch (NoSuchFieldException | IllegalAccessException e) {
718708
throw new RuntimeException(e);
719709
}
720-
710+
final FlagdProvider provider = new FlagdProvider(grpcResolver, true);
721711
return provider;
722712
}
723713

providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/RunConfigCucumberTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@
1818
@IncludeEngines("cucumber")
1919
@SelectFile("test-harness/gherkin/config.feature")
2020
@ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "pretty")
21-
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "dev.openfeature.contrib.providers.flagd.e2e.steps.config")
21+
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "dev.openfeature.contrib.providers.flagd.e2e.steps")
2222
public class RunConfigCucumberTest {}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package dev.openfeature.contrib.providers.flagd.e2e.steps.config;
1+
package dev.openfeature.contrib.providers.flagd.e2e.steps;
22

33
import static org.assertj.core.api.Assertions.assertThat;
44

providers/go-feature-flag/CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
# Changelog
22

3+
## [0.4.1](https://github.com/open-feature/java-sdk-contrib/compare/dev.openfeature.contrib.providers.go-feature-flag-v0.4.0...dev.openfeature.contrib.providers.go-feature-flag-v0.4.1) (2025-01-20)
4+
5+
6+
### 🐛 Bug Fixes
7+
8+
* **deps:** update dependency com.fasterxml.jackson.core:jackson-databind to v2.18.2 ([#1089](https://github.com/open-feature/java-sdk-contrib/issues/1089)) ([9b40e22](https://github.com/open-feature/java-sdk-contrib/commit/9b40e22e57739c7da417f834dd4f6822e6657ca8))
9+
* **deps:** update dependency com.fasterxml.jackson.datatype:jackson-datatype-jsr310 to v2.18.2 ([#1088](https://github.com/open-feature/java-sdk-contrib/issues/1088)) ([34ec5a8](https://github.com/open-feature/java-sdk-contrib/commit/34ec5a83685100ac014def681286c59f0f939188))
10+
* **deps:** update dependency io.reactivex.rxjava3:rxjava to v3.1.10 ([#1083](https://github.com/open-feature/java-sdk-contrib/issues/1083)) ([67d6308](https://github.com/open-feature/java-sdk-contrib/commit/67d63081c8b5f56ce7ac32a30f2bc1e67b6afe5d))
11+
12+
13+
### ✨ New Features
14+
15+
* **go-feature-flag:** Support Exporter Metadata ([#1167](https://github.com/open-feature/java-sdk-contrib/issues/1167)) ([b55a52e](https://github.com/open-feature/java-sdk-contrib/commit/b55a52ecd90b53d25ea259e16fa0ef43fac9dc12))
16+
17+
18+
### 🧹 Chore
19+
20+
* **deps:** update dependency org.apache.logging.log4j:log4j-slf4j2-impl to v2.24.2 ([#1079](https://github.com/open-feature/java-sdk-contrib/issues/1079)) ([804cd45](https://github.com/open-feature/java-sdk-contrib/commit/804cd455d6e9e79e1fa72b003245027ed7450487))
21+
* **deps:** update dependency org.apache.logging.log4j:log4j-slf4j2-impl to v2.24.3 ([#1103](https://github.com/open-feature/java-sdk-contrib/issues/1103)) ([e2b8160](https://github.com/open-feature/java-sdk-contrib/commit/e2b8160dda2b82b43f665753187ab85a4e1abe13))
22+
323
## [0.4.0](https://github.com/open-feature/java-sdk-contrib/compare/dev.openfeature.contrib.providers.go-feature-flag-v0.3.0...dev.openfeature.contrib.providers.go-feature-flag-v0.4.0) (2024-11-21)
424

525

providers/go-feature-flag/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</parent>
1111
<groupId>dev.openfeature.contrib.providers</groupId>
1212
<artifactId>go-feature-flag</artifactId>
13-
<version>0.4.0</version> <!--x-release-please-version -->
13+
<version>0.4.1</version> <!--x-release-please-version -->
1414

1515
<name>go-feature-flag</name>
1616
<description>GO Feature Flag provider for Java</description>

0 commit comments

Comments
 (0)