Skip to content

Commit 5a4533f

Browse files
committed
Preserve headers in more error situations.
1 parent b20c621 commit 5a4533f

2 files changed

Lines changed: 80 additions & 4 deletions

File tree

lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/StreamingSynchronizerImpl.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ private void handleMessage(MessageEvent event) {
229229
fdv2Event = parseFDv2Event(eventName, event.getDataReader());
230230
} catch (SerializationException e) {
231231
logger.error("Failed to parse FDv2 event: {}", LogValues.exceptionSummary(e));
232-
interruptedWithException(e, DataSourceStatusProvider.ErrorKind.INVALID_DATA);
232+
interruptedWithException(e, DataSourceStatusProvider.ErrorKind.INVALID_DATA, event);
233233
return;
234234
}
235235

@@ -240,7 +240,7 @@ private void handleMessage(MessageEvent event) {
240240
} catch (Exception e) {
241241
// Protocol handler threw exception processing the event - treat as invalid data
242242
logger.error("FDv2 protocol handler error: {}", LogValues.exceptionSummary(e));
243-
interruptedWithException(e, DataSourceStatusProvider.ErrorKind.INVALID_DATA);
243+
interruptedWithException(e, DataSourceStatusProvider.ErrorKind.INVALID_DATA, event);
244244
return;
245245
}
246246

@@ -316,15 +316,15 @@ private void handleMessage(MessageEvent event) {
316316
}
317317
}
318318

319-
private void interruptedWithException(Exception e, DataSourceStatusProvider.ErrorKind kind) {
319+
private void interruptedWithException(Exception e, DataSourceStatusProvider.ErrorKind kind, MessageEvent event) {
320320
logger.debug(LogValues.exceptionTrace(e));
321321
DataSourceStatusProvider.ErrorInfo errorInfo = new DataSourceStatusProvider.ErrorInfo(
322322
kind,
323323
0,
324324
e.toString(),
325325
Instant.now()
326326
);
327-
resultQueue.put(FDv2SourceResult.interrupted(errorInfo, getFallback(e)));
327+
resultQueue.put(FDv2SourceResult.interrupted(errorInfo, getFallback(event)));
328328
restartStream();
329329
}
330330

lib/sdk/server/src/test/java/com/launchdarkly/sdk/server/StreamingSynchronizerImplTest.java

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,4 +1001,80 @@ public void bothFdv1FallbackAndEnvironmentIdExtractedFromHeaders() throws Except
10011001
synchronizer.close();
10021002
}
10031003
}
1004+
1005+
@Test
1006+
public void serializationExceptionWithoutFallbackHeader() throws Exception {
1007+
// Verify that fallback is false when header is not present
1008+
// Use malformed JSON that will cause parsing to fail
1009+
String badEvent = makeEvent("server-intent", "{");
1010+
1011+
try (HttpServer server = HttpServer.start(Handlers.all(
1012+
Handlers.SSE.start(),
1013+
Handlers.SSE.event(badEvent),
1014+
Handlers.SSE.leaveOpen()))) {
1015+
1016+
HttpProperties httpProperties = toHttpProperties(clientContext("sdk-key", baseConfig().build()).getHttp());
1017+
SelectorSource selectorSource = mockSelectorSource();
1018+
1019+
StreamingSynchronizerImpl synchronizer = new StreamingSynchronizerImpl(
1020+
httpProperties,
1021+
server.getUri(),
1022+
"/stream",
1023+
testLogger,
1024+
selectorSource,
1025+
null,
1026+
Duration.ofMillis(100)
1027+
);
1028+
1029+
CompletableFuture<FDv2SourceResult> resultFuture = synchronizer.next();
1030+
FDv2SourceResult result = resultFuture.get(5, TimeUnit.SECONDS);
1031+
1032+
assertNotNull(result);
1033+
assertEquals(FDv2SourceResult.ResultType.STATUS, result.getResultType());
1034+
assertEquals(FDv2SourceResult.State.INTERRUPTED, result.getStatus().getState());
1035+
assertEquals(DataSourceStatusProvider.ErrorKind.INVALID_DATA, result.getStatus().getErrorInfo().getKind());
1036+
assertEquals(false, result.isFdv1Fallback());
1037+
1038+
synchronizer.close();
1039+
}
1040+
}
1041+
1042+
@Test
1043+
public void serializationExceptionPreservesFallbackHeader() throws Exception {
1044+
// Test that when SerializationException occurs, the fallback header from the event is preserved
1045+
// Use definitely malformed JSON that will cause parsing to fail
1046+
String badEvent = makeEvent("server-intent", "{");
1047+
1048+
try (HttpServer server = HttpServer.start(Handlers.all(
1049+
Handlers.header("x-ld-fd-fallback", "true"),
1050+
Handlers.SSE.start(),
1051+
Handlers.SSE.event(badEvent),
1052+
Handlers.SSE.leaveOpen()))) {
1053+
1054+
HttpProperties httpProperties = toHttpProperties(clientContext("sdk-key", baseConfig().build()).getHttp());
1055+
SelectorSource selectorSource = mockSelectorSource();
1056+
1057+
StreamingSynchronizerImpl synchronizer = new StreamingSynchronizerImpl(
1058+
httpProperties,
1059+
server.getUri(),
1060+
"/stream",
1061+
testLogger,
1062+
selectorSource,
1063+
null,
1064+
Duration.ofMillis(100)
1065+
);
1066+
1067+
CompletableFuture<FDv2SourceResult> resultFuture = synchronizer.next();
1068+
FDv2SourceResult result = resultFuture.get(5, TimeUnit.SECONDS);
1069+
1070+
assertNotNull(result);
1071+
assertEquals(FDv2SourceResult.ResultType.STATUS, result.getResultType());
1072+
assertEquals(FDv2SourceResult.State.INTERRUPTED, result.getStatus().getState());
1073+
assertEquals(DataSourceStatusProvider.ErrorKind.INVALID_DATA, result.getStatus().getErrorInfo().getKind());
1074+
assertEquals(true, result.isFdv1Fallback());
1075+
1076+
synchronizer.close();
1077+
}
1078+
}
1079+
10041080
}

0 commit comments

Comments
 (0)