Skip to content

Commit f5bad17

Browse files
committed
feat: add gRPC keepalive
Signed-off-by: Todd Baert <[email protected]>
1 parent fa663a2 commit f5bad17

File tree

5 files changed

+26
-1
lines changed

5 files changed

+26
-1
lines changed

Diff for: providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/Config.java

+10
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public final class Config {
1818

1919
static final int DEFAULT_DEADLINE = 500;
2020
static final int DEFAULT_MAX_CACHE_SIZE = 1000;
21+
static final long DEFAULT_KEEP_ALIVE = 0;
2122

2223
static final String RESOLVER_ENV_VAR = "FLAGD_RESOLVER";
2324
static final String HOST_ENV_VAR_NAME = "FLAGD_HOST";
@@ -32,6 +33,7 @@ public final class Config {
3233
static final String DEADLINE_MS_ENV_VAR_NAME = "FLAGD_DEADLINE_MS";
3334
static final String SOURCE_SELECTOR_ENV_VAR_NAME = "FLAGD_SOURCE_SELECTOR";
3435
static final String OFFLINE_SOURCE_PATH = "FLAGD_OFFLINE_FLAG_SOURCE_PATH";
36+
static final String KEEP_ALIVE_ENV_VAR_NAME = "FLAGD_KEEP_ALIVE";
3537

3638
static final String RESOLVER_RPC = "rpc";
3739
static final String RESOLVER_IN_PROCESS = "in-process";
@@ -64,6 +66,14 @@ static int fallBackToEnvOrDefault(String key, int defaultValue) {
6466
}
6567
}
6668

69+
static long fallBackToEnvOrDefault(String key, long defaultValue) {
70+
try {
71+
return System.getenv(key) != null ? Long.parseLong(System.getenv(key)) : defaultValue;
72+
} catch (Exception e) {
73+
return defaultValue;
74+
}
75+
}
76+
6777
static Resolver fromValueProvider(Function<String, String> provider) {
6878
final String resolverVar = provider.apply(RESOLVER_ENV_VAR);
6979
if (resolverVar == null) {

Diff for: providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/FlagdOptions.java

+8
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@ public class FlagdOptions {
9393
@Builder.Default
9494
private String selector = fallBackToEnvOrDefault(Config.SOURCE_SELECTOR_ENV_VAR_NAME, null);
9595

96+
/**
97+
* gRPC client KeepAlive in milliseconds. Disabled with 0.
98+
* Defaults to 0 (disabled).
99+
*
100+
**/
101+
@Builder.Default
102+
private long keepAlive = fallBackToEnvOrDefault(Config.KEEP_ALIVE_ENV_VAR_NAME, Config.DEFAULT_KEEP_ALIVE);
103+
96104
/**
97105
* File source of flags to be used by offline mode.
98106
* Setting this enables the offline mode of the in-process provider.

Diff for: providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/common/ChannelBuilder.java

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import javax.net.ssl.SSLException;
1515
import java.io.File;
16+
import java.util.concurrent.TimeUnit;
1617

1718
/**
1819
* gRPC channel builder helper.
@@ -36,6 +37,8 @@ public static ManagedChannel nettyChannel(final FlagdOptions options) {
3637

3738
return NettyChannelBuilder
3839
.forAddress(new DomainSocketAddress(options.getSocketPath()))
40+
// keepAliveTime: Long.MAX_VALUE disables keepAlive; very small values are increased automatically
41+
.keepAliveTime(options.getKeepAlive() == 0 ? Long.MAX_VALUE : options.getKeepAlive(), TimeUnit.MILLISECONDS)
3942
.eventLoopGroup(new EpollEventLoopGroup())
4043
.channelType(EpollDomainSocketChannel.class)
4144
.usePlaintext()

Diff for: providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/FlagdOptionsTest.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import dev.openfeature.contrib.providers.flagd.resolver.process.storage.MockConnector;
44
import dev.openfeature.contrib.providers.flagd.resolver.process.storage.connector.Connector;
55
import io.opentelemetry.api.OpenTelemetry;
6-
import org.junit.jupiter.api.Disabled;
76
import org.junit.jupiter.api.Test;
87
import org.junitpioneer.jupiter.SetEnvironmentVariable;
98
import org.mockito.Mockito;
@@ -33,6 +32,7 @@ void TestDefaults() {
3332
assertNull(builder.getCustomConnector());
3433
assertNull(builder.getOfflineFlagSourcePath());
3534
assertEquals(Resolver.RPC, builder.getResolverType());
35+
assertEquals(0, builder.getKeepAlive());
3636
}
3737

3838
@Test
@@ -53,6 +53,7 @@ void TestBuilderOptions() {
5353
.openTelemetry(openTelemetry)
5454
.customConnector(connector)
5555
.resolverType(Resolver.IN_PROCESS)
56+
.keepAlive(1000)
5657
.build();
5758

5859
assertEquals("https://hosted-flagd", flagdOptions.getHost());
@@ -67,6 +68,7 @@ void TestBuilderOptions() {
6768
assertEquals(openTelemetry, flagdOptions.getOpenTelemetry());
6869
assertEquals(connector, flagdOptions.getCustomConnector());
6970
assertEquals(Resolver.IN_PROCESS, flagdOptions.getResolverType());
71+
assertEquals(1000, flagdOptions.getKeepAlive());
7072
}
7173

7274

Diff for: providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/resolver/grpc/GrpcConnectorTest.java

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import static org.junit.jupiter.api.Assertions.assertThrows;
66
import static org.mockito.ArgumentMatchers.any;
77
import static org.mockito.ArgumentMatchers.anyInt;
8+
import static org.mockito.ArgumentMatchers.anyLong;
89
import static org.mockito.ArgumentMatchers.anyString;
910
import static org.mockito.ArgumentMatchers.argThat;
1011
import static org.mockito.Mockito.doAnswer;
@@ -277,6 +278,7 @@ private NettyChannelBuilder getMockChannelBuilderSocket() {
277278
when(mockChannelBuilder.eventLoopGroup(any(EventLoopGroup.class))).thenReturn(mockChannelBuilder);
278279
when(mockChannelBuilder.channelType(any(Class.class))).thenReturn(mockChannelBuilder);
279280
when(mockChannelBuilder.usePlaintext()).thenReturn(mockChannelBuilder);
281+
when(mockChannelBuilder.keepAliveTime(anyLong(), any())).thenReturn(mockChannelBuilder);
280282
when(mockChannelBuilder.build()).thenReturn(null);
281283
return mockChannelBuilder;
282284
}

0 commit comments

Comments
 (0)