Skip to content
This repository has been archived by the owner on May 30, 2024. It is now read-only.

Commit

Permalink
Merge pull request #214 from launchdarkly/eb/ch73883/better-client-co…
Browse files Browse the repository at this point in the history
…ntext

5.0 (#2): don't keep the entire LDConfig instance around after creating LDClient
  • Loading branch information
eli-darkly authored Apr 23, 2020
2 parents 1f5eb8a + 532126b commit 2cb1101
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 40 deletions.
40 changes: 33 additions & 7 deletions src/main/java/com/launchdarkly/sdk/server/ClientContextImpl.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
package com.launchdarkly.sdk.server;

import com.launchdarkly.sdk.server.interfaces.ClientContext;
import com.launchdarkly.sdk.server.interfaces.HttpConfiguration;

final class ClientContextImpl implements ClientContext {
private final String sdkKey;
private final LDConfig configuration;
private final HttpConfiguration httpConfiguration;
private final boolean offline;
private final DiagnosticAccumulator diagnosticAccumulator;
private final DiagnosticEvent.Init diagnosticInitEvent;

ClientContextImpl(String sdkKey, LDConfig configuration, DiagnosticAccumulator diagnosticAccumulator) {
this.sdkKey = sdkKey;
this.configuration = configuration;
this.diagnosticAccumulator = diagnosticAccumulator;
this.httpConfiguration = configuration.httpConfig;
this.offline = configuration.offline;
if (!configuration.diagnosticOptOut && diagnosticAccumulator != null) {
this.diagnosticAccumulator = diagnosticAccumulator;
this.diagnosticInitEvent = new DiagnosticEvent.Init(diagnosticAccumulator.dataSinceDate, diagnosticAccumulator.diagnosticId, configuration);
} else {
this.diagnosticAccumulator = null;
this.diagnosticInitEvent = null;
}
}

@Override
Expand All @@ -19,20 +29,36 @@ public String getSdkKey() {
}

@Override
public LDConfig getConfiguration() {
return configuration;
public boolean isOffline() {
return offline;
}

@Override
public HttpConfiguration getHttpConfiguration() {
return httpConfiguration;
}

// Note that this property is package-private - it is only used by SDK internal components, not any
// custom components implemented by an application.
// Note that the following two properties are package-private - they are only used by SDK internal components,
// not any custom components implemented by an application.
DiagnosticAccumulator getDiagnosticAccumulator() {
return diagnosticAccumulator;
}

DiagnosticEvent.Init getDiagnosticInitEvent() {
return diagnosticInitEvent;
}

static DiagnosticAccumulator getDiagnosticAccumulator(ClientContext context) {
if (context instanceof ClientContextImpl) {
return ((ClientContextImpl)context).getDiagnosticAccumulator();
}
return null;
}

static DiagnosticEvent.Init getDiagnosticInitEvent(ClientContext context) {
if (context instanceof ClientContextImpl) {
return ((ClientContextImpl)context).getDiagnosticInitEvent();
}
return null;
}
}
20 changes: 10 additions & 10 deletions src/main/java/com/launchdarkly/sdk/server/Components.java
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ private static final class NullDataSourceFactory implements DataSourceFactory, D

@Override
public DataSource createDataSource(ClientContext context, DataStoreUpdates dataStoreUpdates) {
if (context.getConfiguration().offline) {
if (context.isOffline()) {
// If they have explicitly called offline(true) to disable everything, we'll log this slightly
// more specific message.
LDClient.logger.info("Starting LaunchDarkly client in offline mode");
Expand Down Expand Up @@ -377,7 +377,7 @@ private static final class StreamingDataSourceBuilderImpl extends StreamingDataS
public DataSource createDataSource(ClientContext context, DataStoreUpdates dataStoreUpdates) {
// Note, we log startup messages under the LDClient class to keep logs more readable

if (context.getConfiguration().offline) {
if (context.isOffline()) {
return Components.externalUpdatesOnly().createDataSource(context, dataStoreUpdates);
}

Expand All @@ -395,14 +395,14 @@ public DataSource createDataSource(ClientContext context, DataStoreUpdates dataS

DefaultFeatureRequestor requestor = new DefaultFeatureRequestor(
context.getSdkKey(),
context.getConfiguration().httpConfig,
context.getHttpConfiguration(),
pollUri,
false
);

return new StreamProcessor(
context.getSdkKey(),
context.getConfiguration().httpConfig,
context.getHttpConfiguration(),
requestor,
dataStoreUpdates,
null,
Expand Down Expand Up @@ -435,7 +435,7 @@ private static final class PollingDataSourceBuilderImpl extends PollingDataSourc
public DataSource createDataSource(ClientContext context, DataStoreUpdates dataStoreUpdates) {
// Note, we log startup messages under the LDClient class to keep logs more readable

if (context.getConfiguration().offline) {
if (context.isOffline()) {
return Components.externalUpdatesOnly().createDataSource(context, dataStoreUpdates);
}

Expand All @@ -444,7 +444,7 @@ public DataSource createDataSource(ClientContext context, DataStoreUpdates dataS

DefaultFeatureRequestor requestor = new DefaultFeatureRequestor(
context.getSdkKey(),
context.getConfiguration().httpConfig,
context.getHttpConfiguration(),
baseURI == null ? LDConfig.DEFAULT_BASE_URI : baseURI,
true
);
Expand All @@ -471,12 +471,11 @@ private static final class EventProcessorBuilderImpl extends EventProcessorBuild
implements DiagnosticDescription {
@Override
public EventProcessor createEventProcessor(ClientContext context) {
if (context.getConfiguration().offline) {
if (context.isOffline()) {
return new NullEventProcessor();
}
return new DefaultEventProcessor(
context.getSdkKey(),
context.getConfiguration(),
new EventsConfiguration(
allAttributesPrivate,
capacity,
Expand All @@ -489,8 +488,9 @@ public EventProcessor createEventProcessor(ClientContext context) {
userKeysFlushInterval,
diagnosticRecordingInterval
),
context.getConfiguration().httpConfig,
ClientContextImpl.getDiagnosticAccumulator(context)
context.getHttpConfiguration(),
ClientContextImpl.getDiagnosticAccumulator(context),
ClientContextImpl.getDiagnosticInitEvent(context)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ final class DefaultEventProcessor implements EventProcessor {
private final AtomicBoolean closed = new AtomicBoolean(false);
private volatile boolean inputCapacityExceeded = false;

DefaultEventProcessor(String sdkKey, LDConfig config, EventsConfiguration eventsConfig, HttpConfiguration httpConfig,
DiagnosticAccumulator diagnosticAccumulator) {
DefaultEventProcessor(String sdkKey, EventsConfiguration eventsConfig, HttpConfiguration httpConfig,
DiagnosticAccumulator diagnosticAccumulator, DiagnosticEvent.Init diagnosticInitEvent) {
inbox = new ArrayBlockingQueue<>(eventsConfig.capacity);

ThreadFactory threadFactory = new ThreadFactoryBuilder()
Expand All @@ -68,7 +68,7 @@ final class DefaultEventProcessor implements EventProcessor {
.build();
scheduler = Executors.newSingleThreadScheduledExecutor(threadFactory);

dispatcher = new EventDispatcher(sdkKey, config, eventsConfig, httpConfig, inbox, threadFactory, closed, diagnosticAccumulator);
dispatcher = new EventDispatcher(sdkKey, eventsConfig, httpConfig, inbox, threadFactory, closed, diagnosticAccumulator, diagnosticInitEvent);

Runnable flusher = () -> {
postMessageAsync(MessageType.FLUSH, null);
Expand All @@ -80,7 +80,7 @@ final class DefaultEventProcessor implements EventProcessor {
};
this.scheduler.scheduleAtFixedRate(userKeysFlusher, eventsConfig.userKeysFlushInterval.toMillis(),
eventsConfig.userKeysFlushInterval.toMillis(), TimeUnit.MILLISECONDS);
if (!config.diagnosticOptOut && diagnosticAccumulator != null) {
if (diagnosticAccumulator != null) {
Runnable diagnosticsTrigger = () -> {
postMessageAsync(MessageType.DIAGNOSTIC, null);
};
Expand Down Expand Up @@ -216,11 +216,12 @@ static final class EventDispatcher {

private long deduplicatedUsers = 0;

private EventDispatcher(String sdkKey, LDConfig config, EventsConfiguration eventsConfig, HttpConfiguration httpConfig,
private EventDispatcher(String sdkKey, EventsConfiguration eventsConfig, HttpConfiguration httpConfig,
final BlockingQueue<EventProcessorMessage> inbox,
ThreadFactory threadFactory,
final AtomicBoolean closed,
DiagnosticAccumulator diagnosticAccumulator) {
DiagnosticAccumulator diagnosticAccumulator,
DiagnosticEvent.Init diagnosticInitEvent) {
this.eventsConfig = eventsConfig;
this.diagnosticAccumulator = diagnosticAccumulator;
this.busyFlushWorkersCount = new AtomicInteger(0);
Expand Down Expand Up @@ -274,7 +275,6 @@ public void uncaughtException(Thread t, Throwable e) {
// Set up diagnostics
this.sendDiagnosticTaskFactory = new SendDiagnosticTaskFactory(sdkKey, eventsConfig, httpClient, httpConfig);
diagnosticExecutor = Executors.newSingleThreadExecutor(threadFactory);
DiagnosticEvent.Init diagnosticInitEvent = new DiagnosticEvent.Init(diagnosticAccumulator.dataSinceDate, diagnosticAccumulator.diagnosticId, config);
diagnosticExecutor.submit(sendDiagnosticTaskFactory.createSendDiagnosticTask(diagnosticInitEvent));
} else {
diagnosticExecutor = null;
Expand Down
23 changes: 12 additions & 11 deletions src/main/java/com/launchdarkly/sdk/server/LDClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ public final class LDClient implements LDClientInterface {
private static final String HMAC_ALGORITHM = "HmacSHA256";
static final String CLIENT_VERSION = getClientVersion();

private final LDConfig config;
private final String sdkKey;
private final Evaluator evaluator;
private final FlagChangeEventPublisher flagChangeEventPublisher;
final EventProcessor eventProcessor;
final DataSource dataSource;
final DataStore dataStore;
private final DataStoreStatusProvider dataStoreStatusProvider;
private final boolean offline;

/**
* Creates a new client instance that connects to LaunchDarkly with the default configuration. In most
Expand Down Expand Up @@ -89,11 +89,12 @@ private static final DataModel.Segment getSegment(DataStore store, String key) {
* @param config a client configuration object
*/
public LDClient(String sdkKey, LDConfig config) {
this.config = new LDConfig(checkNotNull(config, "config must not be null"));
checkNotNull(config, "config must not be null");
this.sdkKey = checkNotNull(sdkKey, "sdkKey must not be null");
this.offline = config.offline;

final EventProcessorFactory epFactory = this.config.eventProcessorFactory == null ?
Components.sendEvents() : this.config.eventProcessorFactory;
final EventProcessorFactory epFactory = config.eventProcessorFactory == null ?
Components.sendEvents() : config.eventProcessorFactory;

if (config.httpConfig.getProxy() != null) {
if (config.httpConfig.getProxyAuthentication() != null) {
Expand All @@ -105,7 +106,7 @@ public LDClient(String sdkKey, LDConfig config) {

// Do not create diagnostic accumulator if config has specified is opted out, or if we're not using the
// standard event processor
final boolean useDiagnostics = !this.config.diagnosticOptOut && epFactory instanceof EventProcessorBuilder;
final boolean useDiagnostics = !config.diagnosticOptOut && epFactory instanceof EventProcessorBuilder;
final ClientContextImpl context = new ClientContextImpl(sdkKey, config,
useDiagnostics ? new DiagnosticAccumulator(new DiagnosticId(sdkKey)) : null);

Expand All @@ -128,18 +129,18 @@ public DataModel.Segment getSegment(String key) {

this.flagChangeEventPublisher = new FlagChangeEventPublisher();

DataSourceFactory dataSourceFactory = this.config.dataSourceFactory == null ?
Components.streamingDataSource() : this.config.dataSourceFactory;
DataSourceFactory dataSourceFactory = config.dataSourceFactory == null ?
Components.streamingDataSource() : config.dataSourceFactory;
DataStoreUpdates dataStoreUpdates = new DataStoreUpdatesImpl(dataStore, flagChangeEventPublisher);
this.dataSource = dataSourceFactory.createDataSource(context, dataStoreUpdates);

Future<Void> startFuture = dataSource.start();
if (!this.config.startWait.isZero() && !this.config.startWait.isNegative()) {
if (!config.startWait.isZero() && !config.startWait.isNegative()) {
if (!(dataSource instanceof Components.NullDataSource)) {
logger.info("Waiting up to " + this.config.startWait.toMillis() + " milliseconds for LaunchDarkly client to start...");
logger.info("Waiting up to " + config.startWait.toMillis() + " milliseconds for LaunchDarkly client to start...");
}
try {
startFuture.get(this.config.startWait.toMillis(), TimeUnit.MILLISECONDS);
startFuture.get(config.startWait.toMillis(), TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
logger.error("Timeout encountered waiting for LaunchDarkly client initialization");
} catch (Exception e) {
Expand Down Expand Up @@ -424,7 +425,7 @@ public void flush() {

@Override
public boolean isOffline() {
return config.offline;
return offline;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.launchdarkly.sdk.server.interfaces;

import com.launchdarkly.sdk.server.LDConfig;

/**
* Context information provided by the {@link com.launchdarkly.sdk.server.LDClient} when creating components.
* <p>
Expand All @@ -20,8 +18,14 @@ public interface ClientContext {
public String getSdkKey();

/**
* The client configuration.
* @return the configuration
* True if {@link com.launchdarkly.sdk.server.LDConfig.Builder#offline(boolean)} was set to true.
* @return the offline status
*/
public boolean isOffline();

/**
* The configured networking properties that apply to all components.
* @return the HTTP configuration
*/
public LDConfig getConfiguration();
public HttpConfiguration getHttpConfiguration();
}

0 comments on commit 2cb1101

Please sign in to comment.