Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FFM-8148] - Standardise SDK error codes #158

Merged
merged 2 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>io.harness.featureflags</groupId>
<artifactId>examples</artifactId>
<version>1.2.5</version>
<version>1.3.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>8</maven.compiler.source>
Expand All @@ -33,7 +33,7 @@
<dependency>
<groupId>io.harness</groupId>
<artifactId>ff-java-server-sdk</artifactId>
<version>1.2.5</version>
<version>1.3.0-SNAPSHOT</version>
</dependency>

<dependency>
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>io.harness</groupId>
<artifactId>ff-java-server-sdk</artifactId>
<version>1.2.5</version>
<version>1.3.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Harness Feature Flag Java Server SDK</name>
<description>Harness Feature Flag Java Server SDK</description>
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/io/harness/cf/client/api/AuthService.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.harness.cf.client.api;

import com.google.common.util.concurrent.AbstractScheduledService;
import io.harness.cf.client.common.SdkCodes;
import io.harness.cf.client.connector.Connector;
import io.harness.cf.client.connector.ConnectorException;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -29,6 +30,7 @@ public AuthService(
protected void runOneIteration() {
try {
connector.authenticate();
SdkCodes.infoSdkAuthOk();
callback.onAuthSuccess();
stopAsync();
log.info("Stopping Auth service");
Expand Down
31 changes: 27 additions & 4 deletions src/main/java/io/harness/cf/client/api/Evaluator.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.google.gson.JsonObject;
import com.sangupta.murmur.Murmur3;
import com.sangupta.murmur.MurmurConstants;
import io.harness.cf.client.common.SdkCodes;
import io.harness.cf.client.common.StringUtils;
import io.harness.cf.client.dto.Target;
import io.harness.cf.model.*;
Expand Down Expand Up @@ -411,29 +412,51 @@ public boolean boolVariation(
String identifier, Target target, boolean defaultValue, FlagEvaluateCallback callback) {
final Optional<Variation> variation =
evaluate(identifier, target, FeatureConfig.KindEnum.BOOLEAN, callback);
return variation.map(value -> Boolean.parseBoolean(value.getValue())).orElse(defaultValue);

if (variation.isPresent()) {
return Boolean.parseBoolean(variation.get().getValue());
}

SdkCodes.warnDefaultVariationServed(identifier, target, String.valueOf(defaultValue));
return defaultValue;
}

public String stringVariation(
String identifier, Target target, String defaultValue, FlagEvaluateCallback callback) {
final Optional<Variation> variation =
evaluate(identifier, target, FeatureConfig.KindEnum.STRING, callback);
return variation.map(Variation::getValue).orElse(defaultValue);

if (variation.isPresent()) {
return variation.get().getValue();
}

SdkCodes.warnDefaultVariationServed(identifier, target, defaultValue);
return defaultValue;
}

public double numberVariation(
String identifier, Target target, double defaultValue, FlagEvaluateCallback callback) {
final Optional<Variation> variation =
evaluate(identifier, target, FeatureConfig.KindEnum.INT, callback);
return variation.map(value -> Double.parseDouble(value.getValue())).orElse(defaultValue);

if (variation.isPresent()) {
return Double.parseDouble(variation.get().getValue());
}

SdkCodes.warnDefaultVariationServed(identifier, target, String.valueOf(defaultValue));
return defaultValue;
}

public JsonObject jsonVariation(
String identifier, Target target, JsonObject defaultValue, FlagEvaluateCallback callback) {
final Optional<Variation> variation =
evaluate(identifier, target, FeatureConfig.KindEnum.JSON, callback);
if (variation.isPresent())

if (variation.isPresent()) {
return new Gson().fromJson(variation.get().getValue(), JsonObject.class);
}

SdkCodes.warnDefaultVariationServed(identifier, target, defaultValue.toString());
return defaultValue;
}
}
24 changes: 10 additions & 14 deletions src/main/java/io/harness/cf/client/api/InnerClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import com.google.common.util.concurrent.Service;
import com.google.gson.JsonObject;
import io.harness.cf.client.common.SdkCodes;
import io.harness.cf.client.connector.Connector;
import io.harness.cf.client.connector.HarnessConfig;
import io.harness.cf.client.connector.HarnessConnector;
Expand Down Expand Up @@ -49,8 +50,6 @@ enum Processor {
private boolean streamReady = false;
private boolean metricReady = false;

private static final String MISSING_SDK_KEY = "SDK key cannot be empty!";

private final ConcurrentHashMap<Event, CopyOnWriteArrayList<Consumer<String>>> events =
new ConcurrentHashMap<>();

Expand Down Expand Up @@ -205,7 +204,8 @@ public synchronized void onMetricsFailure() {

@Override
public void onConnected() {
log.info("onConnected triggered");
SdkCodes.infoStreamConnected();

if (pollProcessor.state() == Service.State.RUNNING) {
// refresh any flags that may have gotten out of sync if the SSE connection was down
pollProcessor.retrieveAll();
Expand All @@ -214,7 +214,10 @@ public void onConnected() {
}

@Override
public void onDisconnected() {
public void onDisconnected(String reason) {

SdkCodes.warnStreamDisconnected(reason);

if (!closing && pollProcessor.state() == Service.State.TERMINATED) {
log.info("onDisconnected triggered, starting poller to get latest flags");

Expand All @@ -239,23 +242,16 @@ public void onReady() {
initialize(Processor.STREAM);
}

@Override
public void onError() {
log.info("onError triggered");
// when error happens on updater (stream)
onDisconnected();
}

@Override
public synchronized void onFailure(@NonNull final String error) {
log.info("onFailure triggered [error={}] ", error);
SdkCodes.warnAuthFailedSrvDefaults(error);
failure = true;
notifyAll();
}

@Override
public void update(@NonNull final Message message) {
log.info("update triggered [event={}] ", message.getEvent());
log.debug("update triggered [event={}] ", message.getEvent());
updateProcessor.update(message);
}

Expand Down Expand Up @@ -297,7 +293,7 @@ private synchronized void initialize(@NonNull final Processor processor) {
initialized = true;
notifyAll();
notifyConsumers(Event.READY, null);
log.info("Initialization is complete");
SdkCodes.infoSdkInitOk();
}

protected void notifyConsumers(@NonNull final Event event, final String value) {
Expand Down
8 changes: 5 additions & 3 deletions src/main/java/io/harness/cf/client/api/MetricsProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.google.common.util.concurrent.AbstractScheduledService;
import com.google.common.util.concurrent.AtomicLongMap;
import io.harness.cf.client.common.SdkCodes;
import io.harness.cf.client.common.StringUtils;
import io.harness.cf.client.connector.Connector;
import io.harness.cf.client.connector.ConnectorException;
Expand Down Expand Up @@ -152,7 +153,7 @@ public void sendDataAndResetCache(
}
log.info("Successfully sent analytics data to the server");
} catch (ConnectorException e) {
log.error("Exception while posting metrics to the event server");
SdkCodes.warnPostMetricsFailed(e.getMessage());
}
}
globalTargetSet.addAll(stagingTargetSet);
Expand Down Expand Up @@ -268,13 +269,14 @@ protected Scheduler scheduler() {
}

public void start() {
log.info("Starting MetricsProcessor with request interval: {}", config.getFrequency());
SdkCodes.infoMetricsThreadStarted(config.getFrequency());
startAsync();
}

public void stop() {
log.info("Stopping MetricsProcessor");
log.debug("Stopping MetricsProcessor");
stopAsync();
SdkCodes.infoMetricsThreadExited();
}

public void close() {
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/io/harness/cf/client/api/PollingProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.common.util.concurrent.AbstractScheduledService;
import com.google.common.util.concurrent.MoreExecutors;
import io.harness.cf.client.common.ScheduledServiceStateLogger;
import io.harness.cf.client.common.SdkCodes;
import io.harness.cf.client.connector.Connector;
import io.harness.cf.model.FeatureConfig;
import io.harness.cf.model.Segment;
Expand Down Expand Up @@ -111,15 +112,15 @@ public void start() {
if (isRunning()) {
return;
}
log.info("Starting PollingProcessor with request interval: {}", pollIntervalSeconds);
SdkCodes.infoPollStarted(pollIntervalSeconds);
startAsync();
}

public void stop() {
log.info("Stopping PollingProcessor");
if (isRunning()) {
stopAsync();
log.info("PollingProcessor stopped");
SdkCodes.infoPollingStopped();
}
}

Expand Down
128 changes: 128 additions & 0 deletions src/main/java/io/harness/cf/client/common/SdkCodes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package io.harness.cf.client.common;

import static java.lang.String.valueOf;
import static java.util.Optional.*;

import io.harness.cf.client.dto.Target;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SdkCodes {

public static void errorMissingSdkKey() {
log.error(sdkErrMsg(1002));
}

public static void infoPollStarted(int durationSec) {
log.info(sdkErrMsg(4000, of(valueOf(durationSec * 1000))));
}

public static void infoSdkInitOk() {
log.info(sdkErrMsg(1000));
}

public static void infoSdkAuthOk() {
log.info(sdkErrMsg(2000));
}

public static void infoPollingStopped() {
log.info(sdkErrMsg(4001));
}

public static void infoStreamConnected() {
log.info(sdkErrMsg(5000));
}

public static void infoStreamEventReceived(String eventJson) {
log.info(sdkErrMsg(5002, of(eventJson)));
}

public static void infoMetricsThreadStarted(int intervalSec) {
log.info(sdkErrMsg(7000, of(valueOf(intervalSec * 1000))));
}

public static void infoMetricsThreadExited() {
log.info(sdkErrMsg(7000));
}

public static void warnAuthFailedSrvDefaults(String reason) {
log.warn(sdkErrMsg(2001, Optional.of(reason)));
}

public static void warnAuthRetying(int attempt) {
log.warn(sdkErrMsg(2003, Optional.of(", attempt " + attempt)));
}

public static void warnStreamDisconnected(String reason) {
log.warn(sdkErrMsg(5001, Optional.of(reason)));
}

public static void warnPostMetricsFailed(String reason) {
log.warn(sdkErrMsg(7002, Optional.of(reason)));
}

public static void warnDefaultVariationServed(String identifier, Target target, String def) {
String targetId = (target == null) ? "null" : target.getIdentifier();
String msg = String.format("identifier=%s, target=%s, default=%s", identifier, targetId, def);
log.warn(sdkErrMsg(6001, of(msg)));
}

private static final Map<Integer, String> MAP =
Arrays.stream(
new String[][] {
// SDK_INIT_1xxx
{"1000", "The SDK has successfully initialized"},
{
"1001",
"The SDK has failed to initialize due to the following authentication error:"
},
{"1002", "The SDK has failed to initialize due to a missing or empty API key"},
// SDK_AUTH_2xxx
{"2000", "Authenticated ok"},
{
"2001",
"Authentication failed with a non-recoverable error - defaults will be served"
},
{"2003", "Retrying to authenticate"},
// SDK_POLL_4xxx
{"4000", "Polling started, intervalMs:"},
{"4001", "Polling stopped"},
// SDK_STREAM_5xxx
{"5000", "SSE stream connected ok"},
{"5001", "SSE stream disconnected, reason:"},
{"5002", "SSE event received: "},
{"5003", "SSE retrying to connect in"},
// SDK_EVAL_6xxx
{"6000", "Evaluated variation successfully"},
{"6001", "Default variation was served"},
// SDK_METRICS_7xxx
{"7000", "Metrics thread started, intervalMs: "},
{"7001", "Metrics thread exited"},
{"7002", "Posting metrics failed, reason:"}
})
.collect(Collectors.toMap(entry -> Integer.parseInt(entry[0]), entry -> entry[1]));

private static String sdkErrMsg(int error_code) {
return sdkErrMsg(error_code, Optional.empty());
}

private static String sdkErrMsg(int error_code, Optional<String> appendText) {
return String.format(
"SDKCODE(%s:%s): %s %s",
getErrClass(error_code), error_code, MAP.get(error_code), appendText.orElse(""));
}

private static String getErrClass(int error_code) {
if (error_code >= 1000 && error_code <= 1999) return "init";
else if (error_code >= 2000 && error_code <= 2999) return "auth";
else if (error_code >= 4000 && error_code <= 4999) return "poll";
else if (error_code >= 5000 && error_code <= 5999) return "stream";
else if (error_code >= 6000 && error_code <= 6999) return "eval";
else if (error_code >= 7000 && error_code <= 7999) return "metric";
return "";
}
}
Loading
Loading