diff --git a/README.md b/README.md index 133ebc5..cb71a03 100644 --- a/README.md +++ b/README.md @@ -188,6 +188,17 @@ DynamoDbClient client = AlternatorDynamoDbClient.builder() `connectionAcquisitionTimeoutMs` or `connectionTimeoutMs` to 0 with CRT will fall back to SDK defaults (an info message is logged). +**CRT sync 5xx connection note:** The AWS SDK CRT sync response handler treats HTTP +5xx server errors as a condition where the native CRT connection may be closed instead +of returned to the pool. There is no `AwsCrtHttpClient.Builder` option to disable this; +`maxConcurrency`, idle timeout, TCP keep-alive, and CRT connection health settings do +not change that status-code close policy. In this repository's probe using AWS SDK +2.42.2, five sequential 500 responses reused the same TCP connection locally, while CI +observed one replacement connection across the same five responses. Treat CRT sync 5xx +reuse as best-effort: the current probe does not show one new connection per 5xx, but +application code should still assume a connection can rotate after any 5xx response. +Use Apache sync if strict single-connection reuse after 5xx responses is required. + These settings are applied as defaults before any customizer callback runs, so the customizer can override them if needed. diff --git a/src/test/java/com/scylladb/alternator/internal/HttpClientNon2xxConnectionReuseTest.java b/src/test/java/com/scylladb/alternator/internal/HttpClientNon2xxConnectionReuseTest.java index e1b8af8..b33fb0d 100644 --- a/src/test/java/com/scylladb/alternator/internal/HttpClientNon2xxConnectionReuseTest.java +++ b/src/test/java/com/scylladb/alternator/internal/HttpClientNon2xxConnectionReuseTest.java @@ -1,6 +1,7 @@ package com.scylladb.alternator.internal; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import com.scylladb.alternator.AlternatorConfig; import java.io.IOException; @@ -141,6 +142,19 @@ private void assertConnectionReuse(String clientName, int status, ReuseProbeServ clientName + " status " + status + " should reach the server", REQUESTS, server.requestCount()); + if (allowsCrtSyncServerErrorReconnect(clientName, status)) { + // AWS CRT sync documents 5xx server errors as a condition where a connection may be + // closed instead of returned to the pool. The native path does not rotate on every 5xx + // in this short probe, but CI has observed one replacement connection across five + // sequential 500 responses. + assertTrue( + clientName + " status " + status + " should reuse TCP connections", + server.acceptedConnections() <= 2); + assertTrue( + clientName + " status " + status + " should reuse client TCP ports", + server.uniqueRemotePorts() <= 2); + return; + } assertEquals( clientName + " status " + status + " should reuse one TCP connection", 1, @@ -151,6 +165,10 @@ private void assertConnectionReuse(String clientName, int status, ReuseProbeServ server.uniqueRemotePorts()); } + private boolean allowsCrtSyncServerErrorReconnect(String clientName, int status) { + return "crt-sync".equals(clientName) && status >= 500; + } + private void drainAndClose(AbortableInputStream body) throws IOException { try (AbortableInputStream stream = body) { byte[] buffer = new byte[1024];