Skip to content

Commit fb9d683

Browse files
committedMay 7, 2021
Merge #1626 into 1.0.7
2 parents a5b120e + b79dd4e commit fb9d683

File tree

2 files changed

+40
-10
lines changed

2 files changed

+40
-10
lines changed
 

‎reactor-netty-http/src/main/java/reactor/netty/http/client/HttpClientConnect.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ public void onUncaughtException(Connection connection, Throwable error) {
344344
}
345345
else if (handler.shouldRetry && AbortedException.isConnectionReset(error)) {
346346
HttpClientOperations ops = connection.as(HttpClientOperations.class);
347-
if (ops != null) {
347+
if (ops != null && ops.hasSentHeaders()) {
348348
// In some cases the channel close event may be delayed and thus the connection to be
349349
// returned to the pool and later the eviction functionality to remote it from the pool.
350350
// In some rare cases the connection might be acquired immediately, before the channel close
@@ -353,11 +353,30 @@ else if (handler.shouldRetry && AbortedException.isConnectionReset(error)) {
353353
// Mark the connection as non-persistent here so that it never be returned to the pool and leave
354354
// the channel close event to invalidate it.
355355
ops.markPersistent(false);
356-
ops.retrying = true;
356+
// Disable retry if the headers or/and the body were sent
357+
handler.shouldRetry = false;
358+
if (log.isWarnEnabled()) {
359+
log.warn(format(connection.channel(),
360+
"The connection observed an error, the request cannot be " +
361+
"retried as the headers/body were sent"), error);
362+
}
357363
}
358-
if (log.isDebugEnabled()) {
359-
log.debug(format(connection.channel(),
360-
"The connection observed an error, the request will be retried"), error);
364+
else {
365+
if (ops != null) {
366+
// In some cases the channel close event may be delayed and thus the connection to be
367+
// returned to the pool and later the eviction functionality to remote it from the pool.
368+
// In some rare cases the connection might be acquired immediately, before the channel close
369+
// event and the eviction functionality be able to remove it from the pool, this may lead to I/O
370+
// errors.
371+
// Mark the connection as non-persistent here so that it never be returned to the pool and leave
372+
// the channel close event to invalidate it.
373+
ops.markPersistent(false);
374+
ops.retrying = true;
375+
}
376+
if (log.isDebugEnabled()) {
377+
log.debug(format(connection.channel(),
378+
"The connection observed an error, the request will be retried"), error);
379+
}
361380
}
362381
}
363382
else if (log.isWarnEnabled()) {

‎reactor-netty-http/src/test/java/reactor/netty/http/client/HttpClientTest.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,15 +1264,20 @@ void testExplicitSendMonoErrorOnGet() {
12641264

12651265
@Test
12661266
void testRetryNotEndlessIssue587() throws Exception {
1267-
doTestRetry(false);
1267+
doTestRetry(false, true);
1268+
}
1269+
1270+
@Test
1271+
void testRetryDisabledWhenHeadersSent() throws Exception {
1272+
doTestRetry(false, false);
12681273
}
12691274

12701275
@Test
12711276
void testRetryDisabledIssue995() throws Exception {
1272-
doTestRetry(true);
1277+
doTestRetry(true, false);
12731278
}
12741279

1275-
private void doTestRetry(boolean retryDisabled) throws Exception {
1280+
private void doTestRetry(boolean retryDisabled, boolean expectRetry) throws Exception {
12761281
ExecutorService threadPool = Executors.newCachedThreadPool();
12771282
int serverPort = SocketUtils.findAvailableTcpPort();
12781283
ConnectionResetByPeerServer server = new ConnectionResetByPeerServer(serverPort);
@@ -1295,8 +1300,14 @@ private void doTestRetry(boolean retryDisabled) throws Exception {
12951300
}
12961301

12971302
AtomicReference<Throwable> error = new AtomicReference<>();
1298-
StepVerifier.create(client.get()
1303+
StepVerifier.create(client.request(HttpMethod.GET)
12991304
.uri("/")
1305+
.send((req, out) -> {
1306+
if (expectRetry) {
1307+
return Mono.error(new IOException("Connection reset by peer"));
1308+
}
1309+
return out;
1310+
})
13001311
.responseContent())
13011312
.expectErrorMatches(t -> {
13021313
error.set(t);
@@ -1308,7 +1319,7 @@ private void doTestRetry(boolean retryDisabled) throws Exception {
13081319

13091320
int requestCount = 1;
13101321
int requestErrorCount = 1;
1311-
if (!retryDisabled && !(error.get() instanceof PrematureCloseException)) {
1322+
if (expectRetry && !(error.get() instanceof PrematureCloseException)) {
13121323
requestCount = 2;
13131324
requestErrorCount = 2;
13141325
}

0 commit comments

Comments
 (0)
Please sign in to comment.