From 93638fe5f558c0e0eaba7f9b00282480c340a5b3 Mon Sep 17 00:00:00 2001 From: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Date: Wed, 4 Feb 2026 09:25:59 -0800 Subject: [PATCH] chore: Finish goodbye handling. --- .../launchdarkly/sdk/server/PollingBase.java | 4 +- .../sdk/server/StreamingSynchronizerImpl.java | 5 ++- .../server/datasources/FDv2SourceResult.java | 38 ++++++++++++++++--- .../server/StreamingSynchronizerImplTest.java | 3 ++ 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/PollingBase.java b/lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/PollingBase.java index 5cd1325a..01d3f3de 100644 --- a/lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/PollingBase.java +++ b/lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/PollingBase.java @@ -138,7 +138,9 @@ protected CompletableFuture poll(Selector selector, boolean on return oneShot ? FDv2SourceResult.terminalError(info, fdv1Fallback) : FDv2SourceResult.interrupted(info, fdv1Fallback); } case GOODBYE: - return FDv2SourceResult.goodbye(((FDv2ProtocolHandler.FDv2ActionGoodbye) res).getReason(), fdv1Fallback); + String reason = ((FDv2ProtocolHandler.FDv2ActionGoodbye) res).getReason(); + logger.info("Goodbye was received from the LaunchDarkly connection with reason: '{}'.", reason); + return FDv2SourceResult.goodbye(reason, fdv1Fallback); case NONE: break; case INTERNAL_ERROR: { diff --git a/lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/StreamingSynchronizerImpl.java b/lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/StreamingSynchronizerImpl.java index e0d87734..b902bea2 100644 --- a/lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/StreamingSynchronizerImpl.java +++ b/lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/StreamingSynchronizerImpl.java @@ -279,8 +279,9 @@ private void handleMessage(MessageEvent event) { break; case GOODBYE: - FDv2ProtocolHandler.FDv2ActionGoodbye goodbye = (FDv2ProtocolHandler.FDv2ActionGoodbye) action; - result = FDv2SourceResult.goodbye(goodbye.getReason(), getFallback(event)); + String reason = ((FDv2ProtocolHandler.FDv2ActionGoodbye) action).getReason(); + logger.info("Goodbye was received from the LaunchDarkly connection with reason: '{}'.", reason); + result = FDv2SourceResult.goodbye(reason, getFallback(event)); // We drop this current connection and attempt to restart the stream. restartStream(); break; diff --git a/lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/datasources/FDv2SourceResult.java b/lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/datasources/FDv2SourceResult.java index 6f440c63..a63b1496 100644 --- a/lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/datasources/FDv2SourceResult.java +++ b/lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/datasources/FDv2SourceResult.java @@ -49,6 +49,8 @@ public static class Status { private final State state; private final DataSourceStatusProvider.ErrorInfo errorInfo; + private final String reason; + public State getState() { return state; } @@ -57,9 +59,34 @@ public DataSourceStatusProvider.ErrorInfo getErrorInfo() { return errorInfo; } - public Status(State state, DataSourceStatusProvider.ErrorInfo errorInfo) { + Status(State state, DataSourceStatusProvider.ErrorInfo errorInfo, String reason) { this.state = state; this.errorInfo = errorInfo; + this.reason = reason; + } + + public static Status goodbye(String reason) { + return new Status(State.GOODBYE, null, reason); + } + + public static Status interrupted(DataSourceStatusProvider.ErrorInfo errorInfo) { + return new Status(State.INTERRUPTED, errorInfo, null); + } + + public static Status terminalError(DataSourceStatusProvider.ErrorInfo errorInfo) { + return new Status(State.TERMINAL_ERROR, errorInfo, null); + } + + public static Status shutdown() { + return new Status(State.SHUTDOWN, null, null); + } + + /** + * If the state is GOODBYE, then this will be the reason. Otherwise, it will be null. + * @return the reason, or null + */ + public String getReason() { + return reason; } } @@ -80,21 +107,21 @@ private FDv2SourceResult(DataStoreTypes.ChangeSet public static FDv2SourceResult interrupted(DataSourceStatusProvider.ErrorInfo errorInfo, boolean fdv1Fallback) { return new FDv2SourceResult( null, - new Status(State.INTERRUPTED, errorInfo), + Status.interrupted(errorInfo), ResultType.STATUS, fdv1Fallback); } public static FDv2SourceResult shutdown() { return new FDv2SourceResult(null, - new Status(State.SHUTDOWN, null), + Status.shutdown(), ResultType.STATUS, false); } public static FDv2SourceResult terminalError(DataSourceStatusProvider.ErrorInfo errorInfo, boolean fdv1Fallback) { return new FDv2SourceResult(null, - new Status(State.TERMINAL_ERROR, errorInfo), + Status.terminalError(errorInfo), ResultType.STATUS, fdv1Fallback); } @@ -104,10 +131,9 @@ public static FDv2SourceResult changeSet(DataStoreTypes.ChangeSet result2Future = synchronizer.next();