Skip to content

Commit

Permalink
refactor: Add ConfidenceWrapper for OF
Browse files Browse the repository at this point in the history
  • Loading branch information
fabriziodemaria committed Jun 19, 2024
1 parent accfb22 commit 2857993
Show file tree
Hide file tree
Showing 15 changed files with 103 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
import dev.openfeature.sdk.exceptions.FlagNotFoundError;
import dev.openfeature.sdk.exceptions.GeneralError;
import dev.openfeature.sdk.exceptions.TypeMismatchError;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Status.Code;
import io.grpc.StatusRuntimeException;
import java.util.Map;
Expand All @@ -32,58 +30,26 @@ public class ConfidenceFeatureProvider implements FeatureProvider {
/**
* ConfidenceFeatureProvider constructor
*
* @param confidence an instance of the Confidence
* @param confidenceWrapper obtained via {@link #createConfidenceWrapper(Confidence.Builder)}
*/
public ConfidenceFeatureProvider(Confidence confidence) {
this.confidence = confidence;
public ConfidenceFeatureProvider(ConfidenceWrapper confidenceWrapper) {
this.confidence = confidenceWrapper.confidence;
}

private static final Logger log =
org.slf4j.LoggerFactory.getLogger(ConfidenceFeatureProvider.class);

/**
* ConfidenceFeatureProvider constructor
*
* @param clientSecret generated from the Confidence portal
* @param managedChannel gRPC channel
* @deprecated This constructor is deprecated. Please use {@link
* #ConfidenceFeatureProvider(Confidence)} instead.
*/
@Deprecated()
public ConfidenceFeatureProvider(String clientSecret, ManagedChannel managedChannel) {
this(Confidence.builder(clientSecret).flagResolverManagedChannel(managedChannel).build());
public ConfidenceWrapper createConfidenceWrapper(Confidence.Builder confidenceBuilder) {
return new ConfidenceWrapper(confidenceBuilder.metadata("SDK_ID_JAVA_PROVIDER").build());
}

/**
* ConfidenceFeatureProvider constructor
*
* @param clientSecret generated from the Confidence portal
* @deprecated This constructor is deprecated. Please use {@link
* #ConfidenceFeatureProvider(Confidence)} instead.
*/
@Deprecated()
public ConfidenceFeatureProvider(String clientSecret) {
this(clientSecret, ManagedChannelBuilder.forAddress("edge-grpc.spotify.com", 443).build());
}
private static final Logger log =
org.slf4j.LoggerFactory.getLogger(ConfidenceFeatureProvider.class);

/**
* ConfidenceFeatureProvider constructor that allows you to override the default gRPC host and
* port, used for local resolver.
*
* @param clientSecret generated from the Confidence portal
* @param host gRPC host you want to connect to.
* @param port port of the gRPC host that you want to use.
* @deprecated This constructor is deprecated. Please use {@link
* #ConfidenceFeatureProvider(Confidence)} instead.
*/
@Deprecated()
public ConfidenceFeatureProvider(String clientSecret, String host, int port) {
this(clientSecret, ManagedChannelBuilder.forAddress(host, port).usePlaintext().build());
protected ConfidenceFeatureProvider(Confidence confidence) {
this.confidence = confidence;
}

@Override
public Metadata getMetadata() {
return () -> "com.spotify.confidence.flags.resolver.v1.FlagResolverService";
return () -> "ConfidenceProvider";
}

@Override
Expand Down Expand Up @@ -163,7 +129,7 @@ public ProviderEvaluation<Value> getObjectEvaluation(
Map.of(
OPEN_FEATURE_RESOLVE_CONTEXT_KEY,
ConfidenceValue.Struct.fromProto(evaluationContext)))
.resolveFlags(requestFlagName, true)
.resolveFlags(requestFlagName)
.get();

if (resolveFlagResponse.getResolvedFlagsList().isEmpty()) {
Expand Down Expand Up @@ -245,4 +211,12 @@ private static void handleStatusRuntimeException(StatusRuntimeException e) {
e.getMessage()));
}
}

public static class ConfidenceWrapper {
public final Confidence confidence;

private ConfidenceWrapper(Confidence confidence) {
this.confidence = confidence;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import com.google.protobuf.util.Structs;
import com.google.protobuf.util.Values;
import com.spotify.confidence.Confidence.ConfidenceMetadata;
import com.spotify.confidence.ResolverClientTestUtils.ValueSchemaHolder;
import com.spotify.confidence.shaded.flags.resolver.v1.FlagResolverServiceGrpc.FlagResolverServiceImplBase;
import com.spotify.confidence.shaded.flags.resolver.v1.ResolveFlagsRequest;
Expand Down Expand Up @@ -70,7 +71,8 @@ void beforeEach() {
final FakeEventSenderEngine fakeEventSender = new FakeEventSenderEngine(new FakeClock());
channel = InProcessChannelBuilder.forName(serverName).directExecutor().build();
final FlagResolverClientImpl flagResolver =
new FlagResolverClientImpl(new GrpcFlagResolver("fake-secret", channel));
new FlagResolverClientImpl(
new GrpcFlagResolver("fake-secret", channel, new ConfidenceMetadata("")));
final Confidence confidence = Confidence.create(fakeEventSender, flagResolver);
final FeatureProvider featureProvider = new ConfidenceFeatureProvider(confidence);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ class FakeFlagResolver implements FlagResolver {
public void close() {}

@Override
public CompletableFuture<ResolveFlagsResponse> resolve(
String flag, Struct context, Boolean isProvider) {
public CompletableFuture<ResolveFlagsResponse> resolve(String flag, Struct context) {
this.context = context;
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static class FakeFlagResolverClient implements FlagResolverClient {

@Override
public CompletableFuture<ResolveFlagsResponse> resolveFlags(
String flag, ConfidenceValue.Struct context, Boolean isProvider) {
String flag, ConfidenceValue.Struct context) {
resolves.put(flag, context);
return CompletableFuture.completedFuture(response);
}
Expand Down
35 changes: 28 additions & 7 deletions sdk-java/src/main/java/com/spotify/confidence/Confidence.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public <T> FlagEvaluation<T> getEvaluation(String key, T defaultValue) {
try {
final FlagPath flagPath = getPath(key);
final String requestFlagName = "flags/" + flagPath.getFlag();
final ResolveFlagsResponse response = resolveFlags(requestFlagName, false).get();
final ResolveFlagsResponse response = resolveFlags(requestFlagName).get();
if (response.getResolvedFlagsList().isEmpty()) {
final String errorMessage =
String.format("No active flag '%s' was found", flagPath.getFlag());
Expand Down Expand Up @@ -176,8 +176,8 @@ public <T> FlagEvaluation<T> getEvaluation(String key, T defaultValue) {
}
}

CompletableFuture<ResolveFlagsResponse> resolveFlags(String flagName, Boolean isProvider) {
return client().resolveFlags(flagName, getContext(), isProvider);
CompletableFuture<ResolveFlagsResponse> resolveFlags(String flagName) {
return client().resolveFlags(flagName, getContext());
}

@VisibleForTesting
Expand Down Expand Up @@ -220,8 +220,8 @@ public void flush() {

@Override
public CompletableFuture<ResolveFlagsResponse> resolveFlags(
String flag, ConfidenceValue.Struct context, Boolean isProvider) {
return flagResolverClient.resolveFlags(flag, context, isProvider);
String flag, ConfidenceValue.Struct context) {
return flagResolverClient.resolveFlags(flag, context);
}

@Override
Expand Down Expand Up @@ -301,6 +301,7 @@ public static class Builder {
.keepAliveTime(Duration.ofMinutes(5).getSeconds(), TimeUnit.SECONDS)
.build();
private ManagedChannel flagResolverManagedChannel = DEFAULT_CHANNEL;
private ConfidenceMetadata metadata = new ConfidenceMetadata("SDK_ID_JAVA_CONFIDENCE");

public Builder(@Nonnull String clientSecret) {
this.clientSecret = clientSecret;
Expand All @@ -314,6 +315,16 @@ public Builder flagResolverManagedChannel(String host, int port) {
return this;
}

/**
* NOTE: internal metadata, not meant to be overridden
*
* @param sdkId identifier of the sdk integration in use
*/
public Builder metadata(String sdkId) {
this.metadata = new ConfidenceMetadata(sdkId);
return this;
}

public Builder flagResolverManagedChannel(ManagedChannel managedChannel) {
this.flagResolverManagedChannel = managedChannel;
return this;
Expand All @@ -322,9 +333,9 @@ public Builder flagResolverManagedChannel(ManagedChannel managedChannel) {
public Confidence build() {
final FlagResolverClient flagResolverClient =
new FlagResolverClientImpl(
new GrpcFlagResolver(clientSecret, flagResolverManagedChannel));
new GrpcFlagResolver(clientSecret, flagResolverManagedChannel, metadata));
final EventSenderEngine eventSenderEngine =
new EventSenderEngineImpl(clientSecret, DEFAULT_CHANNEL, Instant::now);
new EventSenderEngineImpl(clientSecret, DEFAULT_CHANNEL, Instant::now, metadata);
closer.register(flagResolverClient);
closer.register(eventSenderEngine);
return new RootInstance(new ClientDelegate(closer, flagResolverClient, eventSenderEngine));
Expand All @@ -343,4 +354,14 @@ private void registerChannelForShutdown(ManagedChannel channel) {
});
}
}

public static class ConfidenceMetadata {
String sdkId;
String sdkVersion;

public ConfidenceMetadata(String sdkId) {
this.sdkId = sdkId;
this.sdkVersion = ConfidenceUtils.getSdkVersion();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.spotify.confidence;

import com.google.common.annotations.VisibleForTesting;
import com.spotify.confidence.Confidence.ConfidenceMetadata;
import com.spotify.confidence.events.v1.Event;
import dev.failsafe.Failsafe;
import dev.failsafe.FailsafeExecutor;
Expand All @@ -17,7 +18,6 @@
import org.slf4j.Logger;

class EventSenderEngineImpl implements EventSenderEngine {

static final String EVENT_NAME_PREFIX = "eventDefinitions/";
static final int DEFAULT_BATCH_SIZE = 25;
static final Duration DEFAULT_MAX_FLUSH_INTERVAL = Duration.ofSeconds(60);
Expand Down Expand Up @@ -64,10 +64,11 @@ class EventSenderEngineImpl implements EventSenderEngine {
pollingThread.start();
}

EventSenderEngineImpl(String clientSecret, ManagedChannel channel, Clock clock) {
EventSenderEngineImpl(
String clientSecret, ManagedChannel channel, Clock clock, ConfidenceMetadata metadata) {
this(
DEFAULT_BATCH_SIZE,
new GrpcEventUploader(clientSecret, clock, channel),
new GrpcEventUploader(clientSecret, clock, channel, metadata),
clock,
DEFAULT_MAX_FLUSH_INTERVAL,
DEFAULT_MAX_MEMORY_CONSUMPTION);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@
interface FlagResolver {
void close();

public CompletableFuture<ResolveFlagsResponse> resolve(
String flag, Struct context, Boolean isProvider);
public CompletableFuture<ResolveFlagsResponse> resolve(String flag, Struct context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@
import java.util.concurrent.CompletableFuture;

interface FlagResolverClient extends Closeable {
CompletableFuture<ResolveFlagsResponse> resolveFlags(
String flag, ConfidenceValue.Struct context, Boolean isProvider);
CompletableFuture<ResolveFlagsResponse> resolveFlags(String flag, ConfidenceValue.Struct context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public FlagResolverClientImpl(FlagResolver grpcFlagResolver) {
}

public CompletableFuture<ResolveFlagsResponse> resolveFlags(
String flagName, ConfidenceValue.Struct context, Boolean isProvider) {
String flagName, ConfidenceValue.Struct context) {
final Struct.Builder evaluationContextBuilder = context.toProto().getStructValue().toBuilder();
if (context.asMap().containsKey(OPEN_FEATURE_RESOLVE_CONTEXT_KEY)) {
final Value openFeatureEvaluationContext =
Expand All @@ -25,7 +25,7 @@ public CompletableFuture<ResolveFlagsResponse> resolveFlags(
evaluationContextBuilder.removeFields(OPEN_FEATURE_RESOLVE_CONTEXT_KEY);
}

return this.grpcFlagResolver.resolve(flagName, evaluationContextBuilder.build(), isProvider);
return this.grpcFlagResolver.resolve(flagName, evaluationContextBuilder.build());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.spotify.confidence;

import com.google.common.collect.ImmutableSet;
import com.spotify.confidence.Confidence.ConfidenceMetadata;
import com.spotify.confidence.events.v1.Event;
import com.spotify.confidence.events.v1.EventsServiceGrpc;
import com.spotify.confidence.events.v1.PublishEventsRequest;
Expand All @@ -16,7 +17,6 @@
import org.slf4j.Logger;

class GrpcEventUploader implements EventUploader {

private final Set<Status.Code> RETRYABLE_STATUS_CODES =
ImmutableSet.of(
Status.Code.UNKNOWN,
Expand All @@ -26,6 +26,8 @@ class GrpcEventUploader implements EventUploader {
Status.Code.ABORTED,
Status.Code.INTERNAL,
Status.Code.DATA_LOSS);
private final Sdk.Builder sdkBuilder =
Sdk.newBuilder().setVersion(ConfidenceUtils.getSdkVersion());
private final String clientSecret;
private final Sdk sdk;
private final ManagedChannel managedChannel;
Expand All @@ -34,16 +36,25 @@ class GrpcEventUploader implements EventUploader {

private static final Logger log = org.slf4j.LoggerFactory.getLogger(GrpcEventUploader.class);

GrpcEventUploader(String clientSecret, Clock clock, ManagedChannel managedChannel) {
GrpcEventUploader(
String clientSecret,
Clock clock,
ManagedChannel managedChannel,
ConfidenceMetadata metadata) {
this.clientSecret = clientSecret;
this.managedChannel = managedChannel;
this.stub = EventsServiceGrpc.newFutureStub(managedChannel);
this.clock = clock;
this.sdk =
Sdk.newBuilder()
.setId(SdkId.SDK_ID_JAVA_CONFIDENCE)
.setVersion(ConfidenceUtils.getSdkVersion())
.build();
this.sdk = getSdkId(metadata);
}

private Sdk getSdkId(ConfidenceMetadata metadata) {
try {
sdkBuilder.setId(SdkId.valueOf(metadata.sdkId));
} catch (IllegalArgumentException e) {
sdkBuilder.setCustomId(metadata.sdkId);
}
return sdkBuilder.build();
}

@Override
Expand Down
Loading

0 comments on commit 2857993

Please sign in to comment.