Skip to content

Commit 428b7d5

Browse files
chore: flagd constructor refactoring (#294)
Signed-off-by: Kavindu Dodanduwa <[email protected]>
1 parent da932af commit 428b7d5

File tree

14 files changed

+538
-243
lines changed

14 files changed

+538
-243
lines changed

providers/flagd/README.md

+63-21
Original file line numberDiff line numberDiff line change
@@ -17,50 +17,92 @@ A feature flag daemon with a Unix philosophy.
1717

1818
## Usage
1919

20-
The `FlagdProvider` communicates with flagd via the gRPC protocol. Instantiate a new FlagdProvider instance, and configure the OpenFeature SDK to use it:
20+
The `FlagdProvider` communicates with flagd via the gRPC protocol. Instantiate a new FlagdProvider instance, and
21+
configure the OpenFeature SDK to use it:
2122

2223
```java
23-
FlagdProvider provider = new FlagdProvider();
24-
OpenFeatureAPI.getInstance().setProvider(provider);
24+
// Create a flagd instance with default options
25+
FlagdProvider flagd = new FlagdProvider();
26+
// Set flagd as the OpenFeature Provider
27+
OpenFeatureAPI.getInstance().setProvider(flagd);
2528
```
2629

27-
Options can be defined in the constructor or as environment variables, with constructor options having the highest precedence.
30+
Options can be defined in the constructor or as environment variables, with constructor options having the highest
31+
precedence.
2832

29-
| Option name | Environment variable name | Type | Default | Values |
30-
| --------------------- | ------------------------------- | ------- | --------- | ------------- |
31-
| host | FLAGD_HOST | string | localhost | |
32-
| port | FLAGD_PORT | number | 8013 | |
33-
| tls | FLAGD_TLS | boolean | false | |
34-
| socketPath | FLAGD_SOCKET_PATH | string | - | |
35-
| certPath | FLAGD_SERVER_CERT_PATH | string | - | |
36-
| cache | FLAGD_CACHE | string | lru | lru,disabled |
37-
| maxCacheSize | FLAGD_MAX_CACHE_SIZE | int | 1000 | |
38-
| maxEventStreamRetries | FLAGD_MAX_EVENT_STREAM_RETRIES | int | 5 | |
33+
Default options can be overridden through a `FlagdOptions` based constructor or set to be picked up from the environment
34+
variables.
35+
36+
### Supported environmental variables
37+
38+
| Option name | Environment variable name | Type | Default | Values |
39+
|-----------------------|--------------------------------|---------|-----------|--------------|
40+
| host | FLAGD_HOST | string | localhost | |
41+
| port | FLAGD_PORT | number | 8013 | |
42+
| tls | FLAGD_TLS | boolean | false | |
43+
| socketPath | FLAGD_SOCKET_PATH | string | null | |
44+
| certPath | FLAGD_SERVER_CERT_PATH | string | null | |
45+
| cache | FLAGD_CACHE | string | lru | lru,disabled |
46+
| maxCacheSize | FLAGD_MAX_CACHE_SIZE | int | 1000 | |
47+
| maxEventStreamRetries | FLAGD_MAX_EVENT_STREAM_RETRIES | int | 5 | |
48+
49+
### OpenTelemetry support
50+
51+
OpenTelemetry support can be enabled either through [automatic instrumentation](https://opentelemetry.io/docs/instrumentation/java/automatic/)
52+
or with [manual instrumentation](https://opentelemetry.io/docs/instrumentation/java/manual/).
53+
54+
For manual instrumentation, flagd provider can be constructed with an `OpenTelemetry` instance.
55+
56+
```java
57+
FlagdOptions options =
58+
FlagdOptions.builder()
59+
.openTelemetry(openTelemetry)
60+
.build();
61+
62+
FlagdProvider flagdProvider = new FlagdProvider(options);
63+
```
64+
65+
Please refer [OpenTelemetry example](https://opentelemetry.io/docs/instrumentation/java/manual/#example) for best
66+
practice guideline.
67+
68+
Telemetry configuration combined with [flagd telemetry ](https://github.com/open-feature/flagd/blob/main/docs/configuration/flagd_telemetry.md)
69+
allows distributed tracing.
3970

4071
### Unix socket support
4172

42-
Unix socket communication with flag is facilitated via usage of the linux-native `epoll` library on `linux-x86_64` only (ARM support is pending relase of `netty-transport-native-epoll` v5). Unix sockets are not supported on other platforms or architectures.
73+
Unix socket communication with flag is facilitated via usage of the linux-native `epoll` library on `linux-x86_64`
74+
only (ARM support is pending relase of `netty-transport-native-epoll` v5). Unix sockets are not supported on other
75+
platforms or architectures.
4376

4477
### Reconnection
4578

46-
Reconnection is supported by the underlying GRPCBlockingStub. If connection to flagd is lost, it will reconnect automatically.
79+
Reconnection is supported by the underlying GRPCBlockingStub. If connection to flagd is lost, it will reconnect
80+
automatically.
4781

4882
### Deadline (gRPC call timeout)
4983

5084
The deadline for an individual flag evaluation can be configured by calling `setDeadline(< deadline in millis >)`.
51-
If the gRPC call is not completed within this deadline, the gRPC call is terminated with the error `DEADLINE_EXCEEDED` and the evaluation will default.
85+
If the gRPC call is not completed within this deadline, the gRPC call is terminated with the error `DEADLINE_EXCEEDED`
86+
and the evaluation will default.
5287
The default deadline is 500ms, though evaluations typically take on the order of 10ms.
5388

5489
### TLS
5590

5691
Though not required in deployments where flagd runs on the same host as the workload, TLS is available.
5792

58-
:warning: Note that there's a [vulnerability](https://security.snyk.io/vuln/SNYK-JAVA-IONETTY-1042268) in [netty](https://github.com/netty/netty), a transitive dependency of the underlying gRPC libraries used in the flagd-provider that fails to correctly validate certificates. This will be addressed in netty v5.
93+
:warning: Note that there's a [vulnerability](https://security.snyk.io/vuln/SNYK-JAVA-IONETTY-1042268)
94+
in [netty](https://github.com/netty/netty), a transitive dependency of the underlying gRPC libraries used in the
95+
flagd-provider that fails to correctly validate certificates. This will be addressed in netty v5.
5996

6097
## Caching
6198

62-
The provider attempts to establish a connection to flagd's event stream (up to 5 times by default). If the connection is successful and caching is enabled each flag returned with reason `STATIC` is cached until an event is received concerning the cached flag (at which point it is removed from cache).
99+
The provider attempts to establish a connection to flagd's event stream (up to 5 times by default). If the connection is
100+
successful and caching is enabled each flag returned with reason `STATIC` is cached until an event is received
101+
concerning the cached flag (at which point it is removed from cache).
63102

64-
On invocation of a flag evaluation (if caching is available) an attempt is made to retrieve the entry from cache, if found the flag is returned with reason `CACHED`.
103+
On invocation of a flag evaluation (if caching is available) an attempt is made to retrieve the entry from cache, if
104+
found the flag is returned with reason `CACHED`.
65105

66-
By default, the provider is configured to use [least recently used (lru)](https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/map/LRUMap.html) caching with up to 1000 entries.
106+
By default, the provider is configured to
107+
use [least recently used (lru)](https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/map/LRUMap.html)
108+
caching with up to 1000 entries.

providers/flagd/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</parent>
1111
<groupId>dev.openfeature.contrib.providers</groupId>
1212
<artifactId>flagd</artifactId>
13-
<version>0.5.8-snapshot</version> <!--x-release-please-version -->
13+
<version>0.5.8</version> <!--x-release-please-version -->
1414

1515
<name>flagd</name>
1616
<description>FlagD provider for Java</description>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package dev.openfeature.contrib.providers.flagd;
2+
3+
final class Config {
4+
static final String DEFAULT_PORT = "8013";
5+
static final String DEFAULT_TLS = "false";
6+
static final String DEFAULT_HOST = "localhost";
7+
8+
static final int DEFAULT_DEADLINE = 500;
9+
static final int DEFAULT_MAX_CACHE_SIZE = 1000;
10+
11+
static final String HOST_ENV_VAR_NAME = "FLAGD_HOST";
12+
static final String PORT_ENV_VAR_NAME = "FLAGD_PORT";
13+
static final String TLS_ENV_VAR_NAME = "FLAGD_TLS";
14+
static final String SOCKET_PATH_ENV_VAR_NAME = "FLAGD_SOCKET_PATH";
15+
static final String SERVER_CERT_PATH_ENV_VAR_NAME = "FLAGD_SERVER_CERT_PATH";
16+
static final String CACHE_ENV_VAR_NAME = "FLAGD_CACHE";
17+
static final String MAX_CACHE_SIZE_ENV_VAR_NAME = "FLAGD_MAX_CACHE_SIZE";
18+
static final String MAX_EVENT_STREAM_RETRIES_ENV_VAR_NAME = "FLAGD_MAX_EVENT_STREAM_RETRIES";
19+
20+
static final String STATIC_REASON = "STATIC";
21+
static final String CACHED_REASON = "CACHED";
22+
23+
static final String FLAG_KEY_FIELD = "flag_key";
24+
static final String CONTEXT_FIELD = "context";
25+
static final String VARIANT_FIELD = "variant";
26+
static final String VALUE_FIELD = "value";
27+
static final String REASON_FIELD = "reason";
28+
29+
static final String LRU_CACHE = "lru";
30+
static final String DEFAULT_CACHE = LRU_CACHE;
31+
32+
static final int DEFAULT_MAX_EVENT_STREAM_RETRIES = 5;
33+
static final int BASE_EVENT_STREAM_RETRY_BACKOFF_MS = 1000;
34+
35+
static String fallBackToEnvOrDefault(String key, String defaultValue) {
36+
return System.getenv(key) != null ? System.getenv(key) : defaultValue;
37+
}
38+
39+
static int fallBackToEnvOrDefault(String key, int defaultValue) {
40+
try {
41+
return System.getenv(key) != null ? Integer.parseInt(System.getenv(key)) : defaultValue;
42+
} catch (Exception e) {
43+
return defaultValue;
44+
}
45+
}
46+
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Defines behaviour required of event stream callbacks.
55
*/
66
interface EventStreamCallback {
7-
void setEventStreamAlive(Boolean alive);
7+
void setEventStreamAlive(boolean alive);
88

99
void restartEventStream() throws Exception;
1010
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
*/
1212
@Slf4j
1313
public class EventStreamObserver implements StreamObserver<EventStreamResponse> {
14-
private EventStreamCallback callback;
15-
private FlagdCache cache;
14+
private final EventStreamCallback callback;
15+
private final FlagdCache cache;
1616

1717
private static final String configurationChange = "configuration_change";
1818
private static final String providerReady = "provider_ready";

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77

88
import dev.openfeature.sdk.ProviderEvaluation;
99

10+
import static dev.openfeature.contrib.providers.flagd.Config.LRU_CACHE;
11+
1012
/**
1113
* Exposes caching mechanism for flag evaluations.
1214
*/
1315
public class FlagdCache {
1416
private Map<String,ProviderEvaluation<? extends Object>> store;
1517
private Boolean enabled = false;
1618

17-
static final String LRU_CACHE = "lru";
1819
static final String DISABLED = "disabled";
1920

2021
FlagdCache(String cache, int maxCacheSize) {
@@ -27,8 +28,7 @@ public class FlagdCache {
2728
return;
2829
case LRU_CACHE:
2930
default:
30-
this.store = Collections
31-
.synchronizedMap(new LRUMap<String, ProviderEvaluation<? extends Object>>(maxCacheSize));
31+
this.store = Collections.synchronizedMap(new LRUMap<>(maxCacheSize));
3232
}
3333

3434
this.enabled = true;

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

+6-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import io.opentelemetry.context.Context;
1212
import io.opentelemetry.context.propagation.TextMapSetter;
1313

14+
import javax.annotation.Nonnull;
1415
import javax.annotation.Nullable;
1516

1617
/**
@@ -22,7 +23,7 @@ final class FlagdGrpcInterceptor implements ClientInterceptor {
2223

2324
private final OpenTelemetry openTelemetry;
2425

25-
FlagdGrpcInterceptor(final OpenTelemetry openTelemetry) {
26+
FlagdGrpcInterceptor(@Nonnull final OpenTelemetry openTelemetry) {
2627
this.openTelemetry = openTelemetry;
2728
}
2829

@@ -32,7 +33,8 @@ final class FlagdGrpcInterceptor implements ClientInterceptor {
3233
final ClientCall<ReqT, RespT> call = channel.newCall(methodDescriptor, callOptions);
3334

3435
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(call) {
35-
@Override public void start(Listener<RespT> responseListener, Metadata headers) {
36+
@Override
37+
public void start(Listener<RespT> responseListener, Metadata headers) {
3638
openTelemetry.getPropagators().getTextMapPropagator().inject(Context.current(), headers, SETTER);
3739
super.start(responseListener, headers);
3840
}
@@ -43,7 +45,8 @@ final class FlagdGrpcInterceptor implements ClientInterceptor {
4345
* Setter implements TextMapSetter with carrier check.
4446
*/
4547
static class Setter implements TextMapSetter<Metadata> {
46-
@Override public void set(@Nullable Metadata carrier, String key, String value) {
48+
@Override
49+
public void set(@Nullable Metadata carrier, String key, String value) {
4750
if (carrier == null) {
4851
return;
4952
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package dev.openfeature.contrib.providers.flagd;
2+
3+
import io.opentelemetry.api.OpenTelemetry;
4+
import lombok.Builder;
5+
import lombok.Getter;
6+
7+
import static dev.openfeature.contrib.providers.flagd.Config.CACHE_ENV_VAR_NAME;
8+
import static dev.openfeature.contrib.providers.flagd.Config.DEFAULT_CACHE;
9+
import static dev.openfeature.contrib.providers.flagd.Config.DEFAULT_HOST;
10+
import static dev.openfeature.contrib.providers.flagd.Config.DEFAULT_MAX_CACHE_SIZE;
11+
import static dev.openfeature.contrib.providers.flagd.Config.DEFAULT_MAX_EVENT_STREAM_RETRIES;
12+
import static dev.openfeature.contrib.providers.flagd.Config.DEFAULT_PORT;
13+
import static dev.openfeature.contrib.providers.flagd.Config.DEFAULT_TLS;
14+
import static dev.openfeature.contrib.providers.flagd.Config.HOST_ENV_VAR_NAME;
15+
import static dev.openfeature.contrib.providers.flagd.Config.MAX_CACHE_SIZE_ENV_VAR_NAME;
16+
import static dev.openfeature.contrib.providers.flagd.Config.MAX_EVENT_STREAM_RETRIES_ENV_VAR_NAME;
17+
import static dev.openfeature.contrib.providers.flagd.Config.PORT_ENV_VAR_NAME;
18+
import static dev.openfeature.contrib.providers.flagd.Config.SERVER_CERT_PATH_ENV_VAR_NAME;
19+
import static dev.openfeature.contrib.providers.flagd.Config.SOCKET_PATH_ENV_VAR_NAME;
20+
import static dev.openfeature.contrib.providers.flagd.Config.TLS_ENV_VAR_NAME;
21+
import static dev.openfeature.contrib.providers.flagd.Config.fallBackToEnvOrDefault;
22+
23+
24+
/**
25+
* FlagdOptions is a builder to build flagd provider options.
26+
* */
27+
@Builder
28+
@Getter
29+
@SuppressWarnings("PMD.TooManyStaticImports")
30+
public class FlagdOptions {
31+
32+
/**
33+
* flagd connection host.
34+
* */
35+
@Builder.Default
36+
private String host = fallBackToEnvOrDefault(HOST_ENV_VAR_NAME, DEFAULT_HOST);
37+
38+
/**
39+
* flagd connection port.
40+
* */
41+
@Builder.Default
42+
private int port = Integer.parseInt(fallBackToEnvOrDefault(PORT_ENV_VAR_NAME, DEFAULT_PORT));
43+
44+
/**
45+
* Use TLS connectivity.
46+
* */
47+
@Builder.Default
48+
private boolean tls = Boolean.parseBoolean(fallBackToEnvOrDefault(TLS_ENV_VAR_NAME, DEFAULT_TLS));
49+
50+
/**
51+
* TLS certificate overriding if TLS connectivity is used.
52+
* */
53+
@Builder.Default
54+
private String certPath = fallBackToEnvOrDefault(SERVER_CERT_PATH_ENV_VAR_NAME, null);
55+
56+
/**
57+
* Unix socket path to flagd.
58+
* */
59+
@Builder.Default
60+
private String socketPath = fallBackToEnvOrDefault(SOCKET_PATH_ENV_VAR_NAME, null);
61+
62+
/**
63+
* Cache type to use. Supports - lru, disabled.
64+
* */
65+
@Builder.Default
66+
private String cacheType = fallBackToEnvOrDefault(CACHE_ENV_VAR_NAME, DEFAULT_CACHE);
67+
68+
/**
69+
* Max cache size.
70+
* */
71+
@Builder.Default
72+
private int maxCacheSize = fallBackToEnvOrDefault(MAX_CACHE_SIZE_ENV_VAR_NAME, DEFAULT_MAX_CACHE_SIZE);
73+
74+
/**
75+
* Max event stream connection retries.
76+
* */
77+
@Builder.Default
78+
private int maxEventStreamRetries =
79+
fallBackToEnvOrDefault(MAX_EVENT_STREAM_RETRIES_ENV_VAR_NAME, DEFAULT_MAX_EVENT_STREAM_RETRIES);
80+
81+
/**
82+
* Inject OpenTelemetry for the library runtime. Providing sdk will initiate distributed tracing for flagd grpc
83+
* connectivity.
84+
* */
85+
private OpenTelemetry openTelemetry;
86+
}

0 commit comments

Comments
 (0)