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

Commit 9bdc82a

Browse files
prepare 6.0.4 release (#295)
1 parent a7152eb commit 9bdc82a

File tree

5 files changed

+44
-3
lines changed

5 files changed

+44
-3
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
All notable changes to the LaunchDarkly Java SDK will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).
44

5+
## [5.10.7] - 2023-01-09
6+
### Fixed:
7+
- If the stream connection failed when the SDK had only partially received a piece of JSON data from the stream, the SDK was sometimes logging a misleading error message about invalid JSON in addition to the normal error message about the connection failure.
8+
59
## [6.0.3] - 2023-01-06
610
### Fixed:
711
- Fixed unintended error behavior when the SDK is being shut down, if streaming is enabled. The symptom was that 1. the SDK could log a misleading message about a network error (in reality this was just the connection being deliberately closed) and 2. an uncaught exception could be thrown from the worker thread that managed that connection. The uncaught exception would be ignored in a default JVM configuration, but it could have more serious consequences in an application that had configured a default exception handler to be triggered by all uncaught exceptions.

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ ext.versions = [
7676
"launchdarklyJavaSdkInternal": "1.0.0",
7777
"launchdarklyLogging": "1.1.0",
7878
"okhttp": "4.9.3", // specify this for the SDK build instead of relying on the transitive dependency from okhttp-eventsource
79-
"okhttpEventsource": "4.0.0",
79+
"okhttpEventsource": "4.1.0",
8080
"slf4j": "1.7.21",
8181
"snakeyaml": "1.32",
8282
"jedis": "2.9.0"

src/main/java/com/launchdarkly/sdk/server/StreamProcessor.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.launchdarkly.eventsource.MessageEvent;
1212
import com.launchdarkly.eventsource.StreamClosedByCallerException;
1313
import com.launchdarkly.eventsource.StreamClosedByServerException;
14+
import com.launchdarkly.eventsource.StreamClosedWithIncompleteMessageException;
1415
import com.launchdarkly.eventsource.StreamEvent;
1516
import com.launchdarkly.eventsource.StreamException;
1617
import com.launchdarkly.eventsource.StreamHttpErrorException;
@@ -275,6 +276,15 @@ private void handleMessage(MessageEvent event, CompletableFuture<Void> initFutur
275276
lastStoreUpdateFailed = false;
276277
dataSourceUpdates.updateStatus(State.VALID, null);
277278
} catch (StreamInputException e) {
279+
if (exceptionHasCause(e, StreamClosedWithIncompleteMessageException.class)) {
280+
// JSON parsing failed because the event was cut off prematurely-- because the
281+
// stream got closed. In this case we should simply throw the event away; the
282+
// closing of the stream will be handled separately on our next pass through
283+
// the loop, and is logged separately. There's no point in logging an error
284+
// about invalid JSON when the real problem is a broken connection; invalid
285+
// JSON is significant only if we think we have a complete message.
286+
return;
287+
}
278288
logger.error("LaunchDarkly service request failed or received invalid data: {}",
279289
LogValues.exceptionSummary(e));
280290
logger.debug(LogValues.exceptionTrace(e));
@@ -303,6 +313,13 @@ private void handleMessage(MessageEvent event, CompletableFuture<Void> initFutur
303313
}
304314
}
305315

316+
private static boolean exceptionHasCause(Throwable e, Class<?> c) {
317+
if (c.isAssignableFrom(e.getClass())) {
318+
return true;
319+
}
320+
return e.getCause() != null && exceptionHasCause(e.getCause(), c);
321+
}
322+
306323
private void handlePut(Reader eventData, CompletableFuture<Void> initFuture)
307324
throws StreamInputException, StreamStoreException {
308325
recordStreamInit(false);

src/test/java/com/launchdarkly/sdk/server/EvalResultTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package com.launchdarkly.sdk.server;
22

3-
import java.util.function.Function;
4-
53
import com.launchdarkly.sdk.EvaluationDetail;
64
import com.launchdarkly.sdk.EvaluationReason;
75
import com.launchdarkly.sdk.LDValue;
86

97
import org.junit.Test;
108

9+
import java.util.function.Function;
10+
1111
import static com.launchdarkly.sdk.EvaluationDetail.NO_VARIATION;
1212
import static com.launchdarkly.sdk.EvaluationReason.ErrorKind.WRONG_TYPE;
1313
import static org.hamcrest.MatcherAssert.assertThat;

src/test/java/com/launchdarkly/sdk/server/StreamProcessorTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,26 @@ public void closingStreamProcessorDoesNotLogNetworkError() throws Exception {
725725
}
726726
}
727727
}
728+
729+
@Test
730+
public void streamFailingWithIncompleteEventDoesNotLogJsonError() throws Exception {
731+
String incompleteEvent = "event: put\ndata: {\"flags\":";
732+
Handler stream1 = Handlers.all(
733+
Handlers.SSE.start(),
734+
Handlers.writeChunkString(incompleteEvent)
735+
);
736+
Handler stream2 = streamResponse(EMPTY_DATA_EVENT);
737+
Handler stream1Then2 = Handlers.sequential(stream1, stream2);
738+
739+
try (HttpServer server = HttpServer.start(stream1Then2)) {
740+
try (StreamProcessor sp = createStreamProcessor(null, server.getUri())) {
741+
sp.start();
742+
dataSourceUpdates.awaitInit();
743+
744+
assertThat(logCapture.awaitMessage(LDLogLevel.ERROR, 0), nullValue());
745+
}
746+
}
747+
}
728748

729749
private void testUnrecoverableHttpError(int statusCode) throws Exception {
730750
Handler errorResp = Handlers.status(statusCode);

0 commit comments

Comments
 (0)