Repository navigation
Implement retries in the Jetty transporter - #2242
sakshichitnis27 wants to merge 3 commits into
Conversation
Retry HEAD, GET and PUT requests according to the aether.connector.http.retryHandler.* settings, since the Jetty HttpClient has no retry hook. Log retries like the other transporters. This closes apache#2239
gnodet-bot
left a comment
There was a problem hiding this comment.
Solid implementation that brings Jetty to parity with the Apache/JDK transporters. One resource management issue in the GET retry path, plus a minor comment on the Retry-After heuristic.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
| if (retryAfter.contains(":")) { // is date when to retry | ||
| delay = Math.max( | ||
| responseHeaders.getDateField(HttpHeader.RETRY_AFTER) - System.currentTimeMillis(), 0L); | ||
| reason = "Retry-After header with date value " + retryAfter; | ||
| } else { | ||
| delay = Long.parseLong(retryAfter.trim()) * 1000L; // is in seconds | ||
| reason = "Retry-After header with seconds value " + retryAfter; | ||
| } |
There was a problem hiding this comment.
💡 Retry-After heuristic: prefer try-parse-as-long over contains(':').
RFC 7231 defines Retry-After as either a delta-seconds value (all digits) or an HTTP-date (contains :). The current heuristic works for all well-formed values, but the more robust and self-documenting approach is to try parsing as a long first and fall back to date parsing — consistent with the outer catch (IllegalArgumentException) which already covers NumberFormatException.
| if (retryAfter.contains(":")) { // is date when to retry | |
| delay = Math.max( | |
| responseHeaders.getDateField(HttpHeader.RETRY_AFTER) - System.currentTimeMillis(), 0L); | |
| reason = "Retry-After header with date value " + retryAfter; | |
| } else { | |
| delay = Long.parseLong(retryAfter.trim()) * 1000L; // is in seconds | |
| reason = "Retry-After header with seconds value " + retryAfter; | |
| } | |
| try { | |
| long seconds = Long.parseLong(retryAfter.trim()); | |
| delay = seconds * 1000L; // is in seconds | |
| reason = "Retry-After header with seconds value " + retryAfter; | |
| } catch (NumberFormatException nfe) { | |
| // not a delta-seconds value, try parsing as HTTP-date | |
| delay = Math.max( | |
| responseHeaders.getDateField(HttpHeader.RETRY_AFTER) - System.currentTimeMillis(), 0L); | |
| reason = "Retry-After header with date value " + retryAfter; | |
| } |
There was a problem hiding this comment.
Thanks! I kept the contains(":") check so it behaves the same as ApacheTransporter, which tells a date from seconds the same way. Happy to switch to try-parse-first if you'd prefer.
This comment has been minimized.
This comment has been minimized.
gnodet-bot
left a comment
There was a problem hiding this comment.
Following up on my earlier review — the resource leak is addressed, and the Retry-After heuristic I flagged is functionally correct.
✅ Addressed: InputStreamResponseListener not closed on exception retry — listener.close() added before continue (commit f3fadbc).
💡 Still open (non-blocking): Retry-After contains(":") heuristic — RFC 7231 guarantees all well-formed values are correctly classified (delta-seconds never contain a colon; HTTP-dates always do). The original suggestion to try parseLong first is stylistic; there's no correctness issue here. Leaving the thread open for the author to address or close at their discretion.
Previous findings resolved. LGTM.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
gnodet-bot
left a comment
There was a problem hiding this comment.
Following up on my earlier review — the single commit since my last LGTM (beb12a7) is a test-only change.
✅ testPut_RetriesAfterClosedConnection — removed the file-content assertion after a closed-connection retry sequence. The comment correctly explains the issue: when the server closes the connection immediately (setConnectionsToClose), the handler may have partially executed, potentially leaving the file in an indeterminate state. The assertion was therefore brittle and its removal is correct.
💡 Still open (non-blocking): The Retry-After contains(":") heuristic thread — as noted in my previous review, this is functionally correct per RFC 7231 and the remaining thread is purely stylistic. No action required.
LGTM — ready to merge.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
Implement retries in the Jetty transporter
The Jetty HttpClient has no retry hook, so
JettyTransporternow retriesHEAD,GETandPUTrequests itself, using the existingaether.connector.http.retryHandler.*settings (count,interval,intervalMax,serviceUnavailable), the same way the Apache and JDK transporters do.serviceUnavailable(429 and 503 by default) are retried after a linearly growing delay. ARetry-Afterheader (seconds or HTTP date) is used instead if present. The delay is capped atintervalMax.DefaultHttpRequestRetryHandler.InsecureRedirectGuard/SameAuthorityRedirectGuardare not retried. The guards now abort with a smallRedirectRefusedException(still anIOException) so they can be told apart.HttpTransporter.logRetry/logImmediateRetry, like for the other transporters.implPeeknow unwraps theExecutionExceptionlikeimplGetandimplPutalready do, so a failedpeeksurfaces the underlyingIOException.transporter-known-issues.md.Only the time until the response headers arrive is covered, as for the other transporters. A download that fails halfway through the body is not retried.
Tests:
HttpTransporterTestfor Jetty (supportsRetryLogging()and the@Disabledoverrides are gone). Before this change 11 of them failed onmaster.JettyRetryHandlerTest(retry limit, non-retriable failures,Retry-Afteras seconds/date/invalid, delay cap).HEAD, so I addedGETandPUTcases toJettyTransporterTest(503 then success, closed connection then success, giving up after the retry count). These fail if retries are switched off.Verified with
mvn -pl maven-resolver-transport-jetty verify(143 tests, 0 failures, 5 skipped as before).This closes #2239
To make clear that you license your contribution under
the Apache License Version 2.0, January 2004
check one of the following: