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

Commit

Permalink
prepare 6.0.4 release (#295)
Browse files Browse the repository at this point in the history
  • Loading branch information
LaunchDarklyReleaseBot authored Jan 10, 2023
1 parent a7152eb commit 9bdc82a
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 3 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

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

## [5.10.7] - 2023-01-09
### Fixed:
- 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.

## [6.0.3] - 2023-01-06
### Fixed:
- 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.
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ ext.versions = [
"launchdarklyJavaSdkInternal": "1.0.0",
"launchdarklyLogging": "1.1.0",
"okhttp": "4.9.3", // specify this for the SDK build instead of relying on the transitive dependency from okhttp-eventsource
"okhttpEventsource": "4.0.0",
"okhttpEventsource": "4.1.0",
"slf4j": "1.7.21",
"snakeyaml": "1.32",
"jedis": "2.9.0"
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/com/launchdarkly/sdk/server/StreamProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.launchdarkly.eventsource.MessageEvent;
import com.launchdarkly.eventsource.StreamClosedByCallerException;
import com.launchdarkly.eventsource.StreamClosedByServerException;
import com.launchdarkly.eventsource.StreamClosedWithIncompleteMessageException;
import com.launchdarkly.eventsource.StreamEvent;
import com.launchdarkly.eventsource.StreamException;
import com.launchdarkly.eventsource.StreamHttpErrorException;
Expand Down Expand Up @@ -275,6 +276,15 @@ private void handleMessage(MessageEvent event, CompletableFuture<Void> initFutur
lastStoreUpdateFailed = false;
dataSourceUpdates.updateStatus(State.VALID, null);
} catch (StreamInputException e) {
if (exceptionHasCause(e, StreamClosedWithIncompleteMessageException.class)) {
// JSON parsing failed because the event was cut off prematurely-- because the
// stream got closed. In this case we should simply throw the event away; the
// closing of the stream will be handled separately on our next pass through
// the loop, and is logged separately. There's no point in logging an error
// about invalid JSON when the real problem is a broken connection; invalid
// JSON is significant only if we think we have a complete message.
return;
}
logger.error("LaunchDarkly service request failed or received invalid data: {}",
LogValues.exceptionSummary(e));
logger.debug(LogValues.exceptionTrace(e));
Expand Down Expand Up @@ -303,6 +313,13 @@ private void handleMessage(MessageEvent event, CompletableFuture<Void> initFutur
}
}

private static boolean exceptionHasCause(Throwable e, Class<?> c) {
if (c.isAssignableFrom(e.getClass())) {
return true;
}
return e.getCause() != null && exceptionHasCause(e.getCause(), c);
}

private void handlePut(Reader eventData, CompletableFuture<Void> initFuture)
throws StreamInputException, StreamStoreException {
recordStreamInit(false);
Expand Down
4 changes: 2 additions & 2 deletions src/test/java/com/launchdarkly/sdk/server/EvalResultTest.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.launchdarkly.sdk.server;

import java.util.function.Function;

import com.launchdarkly.sdk.EvaluationDetail;
import com.launchdarkly.sdk.EvaluationReason;
import com.launchdarkly.sdk.LDValue;

import org.junit.Test;

import java.util.function.Function;

import static com.launchdarkly.sdk.EvaluationDetail.NO_VARIATION;
import static com.launchdarkly.sdk.EvaluationReason.ErrorKind.WRONG_TYPE;
import static org.hamcrest.MatcherAssert.assertThat;
Expand Down
20 changes: 20 additions & 0 deletions src/test/java/com/launchdarkly/sdk/server/StreamProcessorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,26 @@ public void closingStreamProcessorDoesNotLogNetworkError() throws Exception {
}
}
}

@Test
public void streamFailingWithIncompleteEventDoesNotLogJsonError() throws Exception {
String incompleteEvent = "event: put\ndata: {\"flags\":";
Handler stream1 = Handlers.all(
Handlers.SSE.start(),
Handlers.writeChunkString(incompleteEvent)
);
Handler stream2 = streamResponse(EMPTY_DATA_EVENT);
Handler stream1Then2 = Handlers.sequential(stream1, stream2);

try (HttpServer server = HttpServer.start(stream1Then2)) {
try (StreamProcessor sp = createStreamProcessor(null, server.getUri())) {
sp.start();
dataSourceUpdates.awaitInit();

assertThat(logCapture.awaitMessage(LDLogLevel.ERROR, 0), nullValue());
}
}
}

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

0 comments on commit 9bdc82a

Please sign in to comment.