Skip to content

Commit

Permalink
FFM-12087 Move option to harness config
Browse files Browse the repository at this point in the history
  • Loading branch information
erdirowlands committed Oct 4, 2024
1 parent 878f12e commit 92d3f80
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 58 deletions.
24 changes: 0 additions & 24 deletions src/main/java/io/harness/cf/client/api/BaseConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,28 +83,4 @@ public int getFrequency() {
* </pre>
*/
@Builder.Default private final long maxRequestRetry = DEFAULT_REQUEST_RETRIES;

/**
* Indicates whether to flush analytics data when the SDK is closed.
* <p>
* When set to {@code true}, any remaining analytics data (such as metrics)
* will be sent to the server before the SDK is fully closed. If {@code false},
* the data will not be flushed, and any unsent analytics data may be lost.
* <p>
* The default value is {@code false}.
* <p>
* <b>Note:</b> The flush will attempt to send the data in a single request.
* Any failures during this process will not be retried, and the analytics data
* may be lost.
*
* <p>Example usage:
* <pre>
* {@code
* BaseConfig config = BaseConfig.builder()
* .flushAnalyticsOnClose(true)
* .build();
* }
* </pre>
*/
@Builder.Default private final boolean flushAnalyticsOnClose = false;
}
5 changes: 3 additions & 2 deletions src/main/java/io/harness/cf/client/api/InnerClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ protected void setUp(@NonNull final Connector connector, @NonNull final BaseConf
log.info("Starting SDK client with configuration: {}", this.options);
this.connector = connector;
this.connector.setOnUnauthorized(this::onUnauthorized);

// initialization
repository =
new StorageRepository(
Expand All @@ -96,7 +95,9 @@ protected void setUp(@NonNull final Connector connector, @NonNull final BaseConf
authService = new AuthService(this.connector, options.getPollIntervalInSeconds(), this);
pollProcessor =
new PollingProcessor(this.connector, repository, options.getPollIntervalInSeconds(), this);
metricsProcessor = new MetricsProcessor(this.connector, this.options, this);
metricsProcessor =
new MetricsProcessor(
this.connector, this.options, this, connector.getShouldFlushAnalyticsOnClose());
updateProcessor = new UpdateProcessor(this.connector, this.repository, this);

// start with authentication
Expand Down
12 changes: 9 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 @@ -111,13 +111,19 @@ public boolean containsKey(K key) {
private final LongAdder metricsSent = new LongAdder();
private final int maxFreqMapSize;

private final boolean shouldFlushMetricsOnClose;

public MetricsProcessor(
@NonNull Connector connector, @NonNull BaseConfig config, @NonNull MetricsCallback callback) {
@NonNull Connector connector,
@NonNull BaseConfig config,
@NonNull MetricsCallback callback,
boolean shouldFlushMetricsOnClose) {
this.connector = connector;
this.config = config;
this.frequencyMap = new FrequencyMap<>();
this.targetsSeen = ConcurrentHashMap.newKeySet();
this.maxFreqMapSize = clamp(config.getBufferSize(), 2048, MAX_FREQ_MAP_TO_RETAIN);
this.shouldFlushMetricsOnClose = shouldFlushMetricsOnClose;
callback.onMetricsReady();
}

Expand Down Expand Up @@ -303,7 +309,7 @@ public void start() {
}

public void stop() {
if (config.isFlushAnalyticsOnClose()) {
if (shouldFlushMetricsOnClose) {
flushQueue();
}

Expand All @@ -327,7 +333,7 @@ public void close() {
scheduler,
SdkCodes::infoMetricsThreadExited,
errMsg -> {
if (config.isFlushAnalyticsOnClose()) {
if (shouldFlushMetricsOnClose) {
log.warn("Waited for flush to finish {}", errMsg);
} else {
log.warn("Failed to stop metrics scheduler: {}", errMsg);
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/io/harness/cf/client/connector/Connector.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@ public interface Connector {

void close();

boolean getShouldFlushAnalyticsOnClose();

void setIsShuttingDown();
}
78 changes: 50 additions & 28 deletions src/main/java/io/harness/cf/client/connector/HarnessConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,53 @@ public class HarnessConfig {
/** read timeout in minutes for SSE connections */
@Builder.Default long sseReadTimeout = 1;

/**
* list of trusted CAs - for when the given config/event URLs are signed with a private CA. You
* should include intermediate CAs too to allow the HTTP client to build a full trust chain.
*/
@Builder.Default List<X509Certificate> tlsTrustedCAs = null;

/**
* Defines the maximum number of retry attempts for certain types of requests:
* authentication, polling, metrics, and reacting to stream events. If a request fails,
* the SDK will retry up to this number of times before giving up.
* <p>
* - Authentication: Used for retrying authentication requests when the server is unreachable.
* - Polling: Applies to requests that fetch feature flags and target groups periodically.
* - Metrics: Applies to analytics requests for sending metrics data to the server.
* - Reacting to Stream Events: Applies to requests triggered by streamed flag or group changes,
* where the SDK needs to fetch updated flag or group data.
* <p>
* Note: This setting does not apply to streaming requests (either the initial connection or
* reconnecting after a disconnection). Streaming requests will always retry indefinitely
* (infinite retries).
*/
@Builder.Default private long maxRequestRetry = 10;

/**
* Indicates whether to flush analytics data when the SDK is closed.
* <p>
* When set to {@code true}, any remaining analytics data (such as metrics)
* will be sent to the server before the SDK is fully closed. If {@code false},
* the data will not be flushed, and any unsent analytics data may be lost.
* <p>
* The default value is {@code false}.
* <p>
* <b>Note:</b> The flush will attempt to send the data in a single request.
* Any failures during this process will not be retried, and the analytics data
* may be lost.
*
* <p>Example usage:
* <pre>
* {@code
* HarnessConfig harnessConfig = HarnessConfig.builder()
* .flushAnalyticsOnClose(true)
* .build();
* }
* </pre>
*/
@Builder.Default private final boolean flushAnalyticsOnClose = false;

/**
* The timeout for flushing analytics on SDK close.
* <p>
Expand All @@ -47,39 +94,14 @@ public class HarnessConfig {
* <p>Example usage:
* <pre>
* {@code
* // Timeout the analytics flush request in 3000ms (3 seconds)
* HarnessConfig harnessConfig =
* HarnessConfig.builder().flushAnalyticsOnCloseTimeout(3000).build();
*
* // flush analytics on close is enabled via BaseConfig
* BaseConfig config = BaseConfig.builder()
* HarnessConfig harnessConfig = HarnessConfig.builder()
* .flushAnalyticsOnClose(true)
* // Timeout the analytics flush request in 3000ms (3 seconds)
* .flushAnalyticsOnCloseTimeout(3000).build();
* .build();
* }
* </pre>
*/
@Builder.Default private final int flushAnalyticsOnCloseTimeout = 30000;

/**
* list of trusted CAs - for when the given config/event URLs are signed with a private CA. You
* should include intermediate CAs too to allow the HTTP client to build a full trust chain.
*/
@Builder.Default List<X509Certificate> tlsTrustedCAs = null;

/**
* Defines the maximum number of retry attempts for certain types of requests:
* authentication, polling, metrics, and reacting to stream events. If a request fails,
* the SDK will retry up to this number of times before giving up.
* <p>
* - Authentication: Used for retrying authentication requests when the server is unreachable.
* - Polling: Applies to requests that fetch feature flags and target groups periodically.
* - Metrics: Applies to analytics requests for sending metrics data to the server.
* - Reacting to Stream Events: Applies to requests triggered by streamed flag or group changes,
* where the SDK needs to fetch updated flag or group data.
* <p>
* Note: This setting does not apply to streaming requests (either the initial connection or
* reconnecting after a disconnection). Streaming requests will always retry indefinitely
* (infinite retries).
*/
@Builder.Default private long maxRequestRetry = 10;
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class HarnessConnector implements Connector, AutoCloseable {
private final MetricsApi metricsApi;
private final String apiKey;
private final HarnessConfig options;

private final AtomicBoolean isShuttingDown = new AtomicBoolean(false);

private String token;
Expand Down Expand Up @@ -473,6 +474,11 @@ public void setIsShuttingDown() {
this.isShuttingDown.set(true);
}

@Override
public boolean getShouldFlushAnalyticsOnClose() {
return options.isFlushAnalyticsOnClose();
}

private static boolean isNullOrEmpty(String string) {
return string == null || string.trim().isEmpty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ public void close() {
log.debug("LocalConnector closed");
}

@Override
public boolean getShouldFlushAnalyticsOnClose() {
// TODO - do we want to support flush for local connector? need to pass it in somehow
return false;
}

@Override
public void setIsShuttingDown() {
isShuttingDown.set(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ public Response intercept(@NotNull Chain chain) throws IOException {
log.trace("Retry-After header detected: {} seconds", retryAfterHeaderValue);
backOffDelayMs = retryAfterHeaderValue * 1000L;
} else {
// Else fallback to a randomized exponential backoff with a max delay of 1 minute (60,000ms)
// Else fallback to a randomized exponential backoff with a max delay of 1 minute
// (60,000ms)
backOffDelayMs = Math.min(retryBackoffDelay * tryCount, 60000L);
}

Expand Down

0 comments on commit 92d3f80

Please sign in to comment.