Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version=9.4.4
version=9.4.5
SONATYPE_CONNECT_TIMEOUT_SECONDS=120
29 changes: 24 additions & 5 deletions src/main/java/com/configcat/ConfigCatLogMessages.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ final class ConfigCatLogMessages {
* Log message for Config Service Cache Read error. The log eventId is 2200.
*/
public static final String CONFIG_SERVICE_CACHE_READ_ERROR = "Error occurred while reading the cache.";
/**
* Log message for Fetch Failed Due To Unexpected error. The log eventId is 1103.
*/
public static final String FETCH_FAILED_DUE_TO_UNEXPECTED_ERROR = "Unexpected error occurred while trying to fetch config JSON. It is most likely due to a local network issue. Please make sure your application can reach the ConfigCat CDN servers (or your proxy server) over HTTP.";

/**
* Log message for Fetch Failed Due To Invalid Sdk Key error. The log eventId is 1100.
*/
private static final String FETCH_FAILED_DUE_TO_INVALID_SDK_KEY_ERROR = "Your SDK Key seems to be wrong. You can find the valid SDK Key at https://app.configcat.com/sdkkey";

/**
* Log message for Fetch Failed Due To Unexpected error. The log eventId is 1103.
*/
private static final String FETCH_FAILED_DUE_TO_UNEXPECTED_ERROR = "Unexpected error occurred while trying to fetch config JSON. It is most likely due to a local network issue. Please make sure your application can reach the ConfigCat CDN servers (or your proxy server) over HTTP.";

/**
* Log message for Fetch Failed Due To Redirect Loop error. The log eventId is 1104.
*/
Expand Down Expand Up @@ -167,12 +169,29 @@ public static FormattableLogMessage getFetchFailedDueToUnexpectedHttpResponse(fi
* @param connectTimeoutMillis Connect timeout in milliseconds.
* @param readTimeoutMillis Read timeout in milliseconds.
* @param writeTimeoutMillis Write timeout in milliseconds.
* @param cfRayId The http response CF-RAY header value.
* @return The formattable log message.
*/
public static FormattableLogMessage getFetchFailedDueToRequestTimeout(final Integer connectTimeoutMillis, final Integer readTimeoutMillis, final Integer writeTimeoutMillis) {
public static FormattableLogMessage getFetchFailedDueToRequestTimeout(final Integer connectTimeoutMillis, final Integer readTimeoutMillis, final Integer writeTimeoutMillis, final String cfRayId) {
if (cfRayId != null) {
return new FormattableLogMessage("Request timed out while trying to fetch config JSON. Timeout values: [connect: %dms, read: %dms, write: %dms] %s", connectTimeoutMillis, readTimeoutMillis, writeTimeoutMillis, ConfigCatLogMessages.getCFRayIdPostFix(cfRayId));
}
return new FormattableLogMessage("Request timed out while trying to fetch config JSON. Timeout values: [connect: %dms, read: %dms, write: %dms]", connectTimeoutMillis, readTimeoutMillis, writeTimeoutMillis);
}

/**
* Log message for Fetch Failed Due To Unexpected error. The log eventId is 1103.
*
* @param cfRayId The http response CF-RAY header value.
* @return The formattable log message.
*/
public static FormattableLogMessage getFetchFailedDueToUnexpectedError(final String cfRayId) {
if (cfRayId != null) {
return new FormattableLogMessage(FETCH_FAILED_DUE_TO_UNEXPECTED_ERROR + " %s", ConfigCatLogMessages.getCFRayIdPostFix(cfRayId));
}
return new FormattableLogMessage(FETCH_FAILED_DUE_TO_UNEXPECTED_ERROR);
}

/**
* Log message for Fetch Failed Due To Redirect Loop error. The log eventId is 1104.
*
Expand Down
19 changes: 10 additions & 9 deletions src/main/java/com/configcat/ConfigFetcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ private CompletableFuture<FetchResponse> executeFetchAsync(int executionCount, S
}

} catch (Exception exception) {
this.logger.error(1103, ConfigCatLogMessages.FETCH_FAILED_DUE_TO_UNEXPECTED_ERROR, exception);
this.logger.error(1103, ConfigCatLogMessages.getFetchFailedDueToUnexpectedError(fetchResponse.cfRayId()), exception);
return CompletableFuture.completedFuture(fetchResponse);
}

Expand All @@ -98,11 +98,11 @@ private CompletableFuture<FetchResponse> getResponseAsync(final String eTag) {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
int logEventId = 1103;
Object message = ConfigCatLogMessages.FETCH_FAILED_DUE_TO_UNEXPECTED_ERROR;
Object message = ConfigCatLogMessages.getFetchFailedDueToUnexpectedError(null);
if (!isClosed.get()) {
if (e instanceof SocketTimeoutException) {
logEventId = 1102;
message = ConfigCatLogMessages.getFetchFailedDueToRequestTimeout(httpClient.connectTimeoutMillis(), httpClient.readTimeoutMillis(), httpClient.writeTimeoutMillis());
message = ConfigCatLogMessages.getFetchFailedDueToRequestTimeout(httpClient.connectTimeoutMillis(), httpClient.readTimeoutMillis(), httpClient.writeTimeoutMillis(), null);
}
logger.error(logEventId, message, e);
}
Expand All @@ -111,8 +111,9 @@ public void onFailure(@NotNull Call call, @NotNull IOException e) {

@Override
public void onResponse(@NotNull Call call, @NotNull Response response) {
String cfRayId = null;
try (ResponseBody body = response.body()) {
String cfRayId = response.header("CF-RAY");
cfRayId = response.header("CF-RAY");
if (response.code() == 200) {
String content = body != null ? body.string() : null;
String eTag = response.header("ETag");
Expand Down Expand Up @@ -140,13 +141,13 @@ public void onResponse(@NotNull Call call, @NotNull Response response) {
future.complete(FetchResponse.failed(formattableLogMessage, false, cfRayId));
}
} catch (SocketTimeoutException e) {
FormattableLogMessage formattableLogMessage = ConfigCatLogMessages.getFetchFailedDueToRequestTimeout(httpClient.connectTimeoutMillis(), httpClient.readTimeoutMillis(), httpClient.writeTimeoutMillis());
FormattableLogMessage formattableLogMessage = ConfigCatLogMessages.getFetchFailedDueToRequestTimeout(httpClient.connectTimeoutMillis(), httpClient.readTimeoutMillis(), httpClient.writeTimeoutMillis(), cfRayId);
logger.error(1102, formattableLogMessage, e);
future.complete(FetchResponse.failed(formattableLogMessage, false, null));
future.complete(FetchResponse.failed(formattableLogMessage, false, cfRayId));
} catch (Exception e) {
String message = ConfigCatLogMessages.FETCH_FAILED_DUE_TO_UNEXPECTED_ERROR;
logger.error(1103, message, e);
future.complete(FetchResponse.failed(message, false, null));
FormattableLogMessage formattableLogMessage = ConfigCatLogMessages.getFetchFailedDueToUnexpectedError(cfRayId);
logger.error(1103, formattableLogMessage, e);
future.complete(FetchResponse.failed(formattableLogMessage, false, cfRayId));
}
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/configcat/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ private Constants() { /* prevent from instantiation*/ }
static final long DISTANT_PAST = 0;
static final String CONFIG_JSON_NAME = "config_v6.json";
static final String SERIALIZATION_FORMAT_VERSION = "v2";
static final String VERSION = "9.4.4";
static final String VERSION = "9.4.5";

static final String SDK_KEY_PROXY_PREFIX = "configcat-proxy/";
static final String SDK_KEY_PREFIX = "configcat-sdk-1";
Expand Down
59 changes: 59 additions & 0 deletions src/test/java/com/configcat/ConfigFetcherTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import okhttp3.OkHttpClient;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.SocketPolicy;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -85,6 +86,64 @@
fetch.close();
}

@Test
public void fetchTimeOutExceptionContainsCFRayIdIfPresented() throws IOException, ExecutionException, InterruptedException {

Check warning on line 90 in src/test/java/com/configcat/ConfigFetcherTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this 'public' modifier.

See more on https://sonarcloud.io/project/issues?id=configcat_java-sdk&issues=AZ2L0rKP6qVIpyacRuMY&open=AZ2L0rKP6qVIpyacRuMY&pullRequest=74

ConfigFetcher fetch = new ConfigFetcher(new OkHttpClient.Builder()
.readTimeout(1, TimeUnit.SECONDS)
.build(),
logger,
"",
this.server.url("/").toString(),
false,
PollingModes.manualPoll().getPollingIdentifier());

this.server.enqueue(new MockResponse().setBody("test").setHeader("CF-RAY", "12345").setBodyDelay(2, TimeUnit.SECONDS));
FetchResponse response = fetch.fetchAsync(null).get();
assertTrue(response.isFailed());
assertTrue(response.entry().isEmpty());
assertTrue(response.entry().getConfig().isEmpty());

assertTrue(response.error().toString().contains("Request timed out while trying to fetch config JSON."));
assertTrue(response.error().toString().contains("(Ray ID: 12345)"));
assertEquals("12345", response.cfRayId());

fetch.close();
}

@Test
public void fetchUnexpectedErrorExceptionContainsCFRayIdIfPresented() throws IOException, ExecutionException, InterruptedException {

Check warning on line 115 in src/test/java/com/configcat/ConfigFetcherTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this 'public' modifier.

See more on https://sonarcloud.io/project/issues?id=configcat_java-sdk&issues=AZ2L0rKP6qVIpyacRuMZ&open=AZ2L0rKP6qVIpyacRuMZ&pullRequest=74

ConfigFetcher fetch = new ConfigFetcher(
new OkHttpClient
.Builder()
.readTimeout(1, TimeUnit.SECONDS)
.build(),
logger,
"",
this.server.url("/").toString(),
false,
PollingModes.manualPoll().getPollingIdentifier());

this.server.enqueue(
new MockResponse()
.setResponseCode(200)
.setHeader("CF-RAY", "12345")
.setBody("test")
.setSocketPolicy(SocketPolicy.DISCONNECT_DURING_RESPONSE_BODY));

FetchResponse response = fetch.fetchAsync(null).get();
assertTrue(response.isFailed());
assertTrue(response.entry().isEmpty());
assertTrue(response.entry().getConfig().isEmpty());

assertTrue(response.error().toString().contains("Unexpected error occurred while trying to fetch config JSON."));
assertTrue(response.error().toString().contains("(Ray ID: 12345)"));
assertEquals("12345", response.cfRayId());

fetch.close();
}

@Test
public void fetchedETagNotUpdatesCache() throws Exception {
this.server.enqueue(new MockResponse().setResponseCode(200).setBody(TEST_JSON).setHeader("ETag", "fakeETag"));
Expand Down