Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
19d9c02
chore: adds fdv2 payload parsing and protocol handling
tanderson-ld Jan 12, 2026
fbea872
adding package info files and fixing package name issue
tanderson-ld Jan 12, 2026
adcaa0e
more checkstyle fixes
tanderson-ld Jan 12, 2026
f2b209d
chore: Add interfaces for synchronizer/initializer.
kinyoklion Jan 13, 2026
8c115cc
Merge branch 'main' into rlamb/add-fdv2-data-source-interfaces
kinyoklion Jan 13, 2026
de2fded
Revert version change
kinyoklion Jan 13, 2026
98d3b39
feat: Add FDv2 polling support.
kinyoklion Jan 13, 2026
da3c639
Merge remote-tracking branch 'origin' into rlamb/add-fdv2-data-source…
kinyoklion Jan 13, 2026
8fb88ed
WIP: Polling initializer/synchronizer.
kinyoklion Jan 14, 2026
da27015
Use updated internal lib.
kinyoklion Jan 14, 2026
aba46ef
Update comment
kinyoklion Jan 14, 2026
7401331
Add termination.
kinyoklion Jan 14, 2026
bba0cdc
Remove test file that isn't ready.
kinyoklion Jan 14, 2026
89bd017
Polling tests and some fixes.
kinyoklion Jan 14, 2026
228f3e6
Try pre block.
kinyoklion Jan 14, 2026
9469b23
Add streaming path.
kinyoklion Jan 14, 2026
9a450e6
Merge branch 'main' of github.com:launchdarkly/java-core into rlamb/a…
kinyoklion Jan 14, 2026
4b8313b
Use the DataStoreTypes.ChangeSet type for data source results.
kinyoklion Jan 14, 2026
31eb13e
Make iterable async queue package private.
kinyoklion Jan 14, 2026
4a2fe3b
Revert Version.java
kinyoklion Jan 14, 2026
3428591
Add comments to SelectorSource.
kinyoklion Jan 14, 2026
ff60216
Revert build.gradle.
kinyoklion Jan 14, 2026
e985f80
Update launchdarklyJavaSdkInternal version to 1.6.1
kinyoklion Jan 14, 2026
a956484
Move mermaid out of doc comment.
kinyoklion Jan 14, 2026
ff2376e
Merge branch 'rlamb/add-fdv2-data-source-interfaces' of github.com:la…
kinyoklion Jan 14, 2026
194c30c
PR feedback.
kinyoklion Jan 14, 2026
707fe0e
Implement more shutdown logic.
kinyoklion Jan 14, 2026
cb79f5e
Change null check.
kinyoklion Jan 14, 2026
b8c5389
PR feedback.
kinyoklion Jan 15, 2026
a90b536
Merge branch 'main' into rlamb/add-fdv2-data-source-interfaces
kinyoklion Jan 15, 2026
8d3e869
PR feedback
kinyoklion Jan 15, 2026
295138a
Merge branch 'rlamb/add-fdv2-data-source-interfaces' of github.com:la…
kinyoklion Jan 15, 2026
ff02c1e
Don't double queue async items
kinyoklion Jan 15, 2026
f805c7e
More comments
kinyoklion Jan 15, 2026
71130ac
PR feedback
kinyoklion Jan 15, 2026
bd8e72b
Fix polling recoverable logic error.
kinyoklion Jan 15, 2026
ff95a85
Better testing
kinyoklion Jan 15, 2026
fd6c3af
Guard source shutdown
kinyoklion Jan 15, 2026
8243b82
More safe closing.
kinyoklion Jan 15, 2026
962afb7
Correct serialization error type.
kinyoklion Jan 15, 2026
fc24f63
Polling better goodbye handling.
kinyoklion Jan 15, 2026
e6edc88
Fix exception type.
kinyoklion Jan 15, 2026
1821373
Fix early return
kinyoklion Jan 15, 2026
bc10b18
EMPTY selector.
kinyoklion Jan 15, 2026
47d55c3
More PR feedback.
kinyoklion Jan 15, 2026
201a92c
Remove unsafe cast from throwable to exception.
kinyoklion Jan 15, 2026
117b85c
Async iterable tests.
kinyoklion Jan 15, 2026
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package com.launchdarkly.sdk.server.datasources;
import com.launchdarkly.sdk.internal.fdv2.sources.FDv2ChangeSet;
import com.launchdarkly.sdk.server.interfaces.DataSourceStatusProvider;

/**
* This type is currently experimental and not subject to semantic versioning.
* <p>
* The result type for FDv2 initializers and synchronizers. An FDv2 initializer produces a single result, while
* an FDv2 synchronizer produces a stream of results.
*/
public class FDv2SourceResult {
public enum State {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want running in this enum?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I shouldn't call it State. Its more like a notification of change, and it doesn't represents valid/running because that is handled by a changeset.

/**
* The data source has encountered an interruption and will attempt to reconnect.
Comment thread
kinyoklion marked this conversation as resolved.
Outdated
*/
INTERRUPTED,
/**
* The data source has been shut down and will not produce any further results.
*/
SHUTDOWN,
/**
* The data source has encountered a terminal error and will not produce any further results.
*/
TERMINAL_ERROR,
/**
* The data source has been instructed to disconnect and will not produce any further results.
*/
GOODBYE,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current description of GOODBYE and SHUTDOWN leaves room for me to think GOODBYE -> SHUTDOWN could be a thing.

I see the diagrams in the specific ones down below that shows that is not possible, but the enum details make it look like it could be?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GOODBYE is effectively a more specific shutdown. We didn't handle it in .Net because SDKs generally don't seem to have handled it yet, but it also is really hard to handle with data source updates.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically in .Net we had an overload broad OFF and it is hard to get the correct behavior because there were are really 2-3 different meanings. Overall we don't need to emit any data source status in most situations for something being shutdown or something being told to exit by flag delivery (but we may handle them different, I am still unsure how to handle goodbye).

SHUTDOWN means I asked the thing to shutdown.
GOODBYE means that FD or some external source asked it to disconnect. Having it different means we can decide to do something different. (I think just by entering this situation we handle most of the problems, because we can be like, cool we aren't running anymore, I don't care about this disconnect I just got from the event source.)
TERMINAL_ERROR means something has gone wrong.

}

public enum ResultType {
/**
* The source has emitted a change set. This implies that the source is valid.
*/
CHANGE_SET,
/**
* The source is emitting a status which indicates a transition from being valid to being in some kind
* of error state. The source will emit a CHANGE_SET if it becomes valid again.
*/
STATUS,
}

/**
* Represents a change in the status of the source.
*/
public static class Status {
private final State state;
private final DataSourceStatusProvider.ErrorInfo errorInfo;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't particularly care for this type, but also we may not want what is effectively a duplicate.


public State getState() {
return state;
}

public DataSourceStatusProvider.ErrorInfo getErrorInfo() {
return errorInfo;
}

public Status(State state, DataSourceStatusProvider.ErrorInfo errorInfo) {
this.state = state;
this.errorInfo = errorInfo;
}
}
private final FDv2ChangeSet changeSet;
private final Status status;

private final ResultType resultType;

private FDv2SourceResult(FDv2ChangeSet changeSet, Status status, ResultType resultType) {
this.changeSet = changeSet;
this.status = status;
this.resultType = resultType;
}

public static FDv2SourceResult interrupted(DataSourceStatusProvider.ErrorInfo errorInfo) {
return new FDv2SourceResult(null, new Status(State.INTERRUPTED, errorInfo), ResultType.STATUS);
}

public static FDv2SourceResult shutdown(DataSourceStatusProvider.ErrorInfo errorInfo) {
return new FDv2SourceResult(null, new Status(State.SHUTDOWN, errorInfo), ResultType.STATUS);
}

public static FDv2SourceResult changeSet(FDv2ChangeSet changeSet) {
return new FDv2SourceResult(changeSet, null, ResultType.CHANGE_SET);
}

public ResultType getResultType() {
return resultType;
}

public Status getStatus() {
return status;
}

public FDv2ChangeSet getChangeSet() {
return changeSet;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.launchdarkly.sdk.server.datasources;

import java.util.concurrent.CompletableFuture;

/**
* This type is currently experimental and not subject to semantic versioning.
* <p>
* Interface for an asynchronous data source initializer.
* <p>
* An initializer will run and produce a single result. If the initializer is successful, then it should emit a result
* containing a change set. If the initializer fails, then it should emit a status result describing the error.
* <p>
* [START]
* │
* ▼
* ┌─────────────┐
* │ RUNNING │──┐
* └─────────────┘ │
* │ │ │ │ │
* │ │ │ │ └──► SHUTDOWN ───► [END]
* │ │ │ │
* │ │ │ └─────► INTERRUPTED ───► [END]
* │ │ │
* │ │ └─────────► CHANGESET ───► [END]
* │ │
* │ └─────────────► TERMINAL_ERROR ───► [END]
* │
* └─────────────────► GOODBYE ───► [END]
*
* <code>
* stateDiagram-v2
* [*] --> RUNNING
* RUNNING --> SHUTDOWN
* RUNNING --> INTERRUPTED
* RUNNING --> CHANGESET
* RUNNING --> TERMINAL_ERROR
* RUNNING --> GOODBYE
* SHUTDOWN --> [*]
* INTERRUPTED --> [*]
* CHANGESET --> [*]
* TERMINAL_ERROR --> [*]
* GOODBYE --> [*]
* </code>
*/
public interface Initializer {
/**
* Run the initializer to completion.
* @return The result of the initializer.
*/
CompletableFuture<FDv2SourceResult> run();

/**
* Shutdown the initializer. The initializer should emit a status event with a SHUTDOWN state as soon as possible.
* If the initializer has already completed, or is in the process of completing, this method should have no effect.
*/
void shutdown();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.launchdarkly.sdk.server.datasources;

import java.util.concurrent.CompletableFuture;

/**
* This type is currently experimental and not subject to semantic versioning.
* <p>
* Interface for an asynchronous data source synchronizer.
* <p>
* A synchronizer will run and produce a stream of results. When it experiences a temporary failure, it will emit a
* status event indicating that it is INTERRUPTED, while it attempts to resolve its failure. When it receives data,
* it should emit a result containing a change set. When the data source is shut down gracefully, it should emit a
* status event indicating that it is SHUTDOWN.
* <p>
* [START]
* │
* ▼
* ┌─────────────┐
* ┌─►│ RUNNING │──┐
* │ └─────────────┘ │
* │ │ │ │ │ │
* │ │ │ │ │ └──► SHUTDOWN ───► [END]
* │ │ │ │ │
* │ │ │ │ └──────► TERMINAL_ERROR ───► [END]
* │ │ │ │
* │ │ │ └──────────► GOODBYE ───► [END]
* │ │ │
* │ │ └──────────────► CHANGE_SET ───┐
* │ │ │
* │ └──────────────────► INTERRUPTED ──┤
* │ │
* └──────────────────────────────────────┘
* <p>
* <code>
* stateDiagram-v2
* [*] --> RUNNING
* RUNNING --> SHUTDOWN
* SHUTDOWN --> [*]
* RUNNING --> TERMINAL_ERROR
* TERMINAL_ERROR --> [*]
* RUNNING --> GOODBYE
* GOODBYE --> [*]
* RUNNING --> CHANGE_SET
* CHANGE_SET --> RUNNING
* RUNNING --> INTERRUPTED
* INTERRUPTED --> RUNNING
* </code>
*/
interface Synchronizer {
/**
* Get the next result from the stream.
* @return a future that will complete when the next result is available
*/
CompletableFuture<FDv2SourceResult> next();

/**
* Shutdown the synchronizer. The synchronizer should emit a status event with a SHUTDOWN state as soon as possible
* and then stop producing further results. If the synchronizer involves a resource, such as a network connection,
* then those resources should be released.
* If the synchronizer has already completed, or is in the process of completing, this method should have no effect.
*/
void shutdown();
}
Loading