New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WAGON-526] making the retry handle of http client configurable #37
[WAGON-526] making the retry handle of http client configurable #37
Conversation
Very nice! Could you comment more on how to use this in practice to improve reliability w.r.t. common network issues? Is the default behavior changed? |
@jkff default didnt change (backwd compat but open to suggestions) idea is to add system properties to maven (MAVEN_OPTS). Here are some samples:
Note that |
I see. So, for example, what's the shortest way to configure this to simply retry everything, including socket exceptions, host resolution exceptions etc? (what we want in Beam builds when downloading artifacts) Would it be |
I guess
can be a good start |
Wait: the default one would give current behavior, which doesn't retry on socket errors. Did you mean Anyway: hope that some of the maintainers can chime in perhaps? |
Small misunderstanding: default behavior is the current one but default (same for standard) clasq value actually references the name of the impl - |
interesting feature. I wonder you could add some documentation maybe here: http://maven.apache.org/wagon/wagon-providers/wagon-http/ |
@olamy updated site apt |
There is bit of a chaos now. I know that the Deploy Plugin supports something similar and people are requesting the same feature for this problem area. I'll collect and have a look at it. |
Is there anything going on with this PR? If it's stale, it might be reasonable to close it and reopen later. We're no longer even using Maven in our project so this PR is not a priority for us. |
@jkff sure, this was done here to not be beam specific since it happens for multiple projects |
@rmannibucau maybe you can rebase as I can see some conflicts |
My bad, I lost completely track of this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks quite good. Some oddities remain.
System.getProperty( "maven.wagon.http.retryhandler.class", "auto" ); | ||
|
||
/** | ||
* true if it's OK to retry non-idempotent requests that have been sent. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What makes you think that this applies to non-idemponent methods? The HttpRequestRetryHandler
doesn't even mention them.
* The type of the retry handler, default to DefaultHttpRequestRetryHandler. | ||
* Values can be default, standard (StandardHttpRequestRetryHandler), or a fully qualified name class. | ||
* | ||
* @since 3.0.1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update this throughout to 3.2 if this one will be merged.
* @since 3.0.1 | ||
*/ | ||
private static final String RETRY_HANDLER_CLASS = | ||
System.getProperty( "maven.wagon.http.retryhandler.class", "auto" ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks wrong to me. Having non-recoverable methods to be retriable by default. We have to be idiotproof and support here standard with StandardHttpRequestRetryHandler
.
}; | ||
case "standard": | ||
return new StandardHttpRequestRetryHandler( RETRY_HANDLER_COUNT, RETRY_HANDLER_REQUEST_SENT_ENABLED ); | ||
case "auto": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't accept this for the reasons above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changing to standard
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be dropped completely.
switch ( RETRY_HANDLER_CLASS ) | ||
{ | ||
case "default": | ||
if ( DEFAULT_NON_RETRYABLE_CLASSES.equals( RETRY_HANDLER_EXCEPTIONS ) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is deemed to fail if the comparison does not happen in order.
return new DefaultHttpRequestRetryHandler( | ||
RETRY_HANDLER_COUNT, RETRY_HANDLER_REQUEST_SENT_ENABLED ); | ||
} | ||
return new DefaultHttpRequestRetryHandler( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is is really smart to provide something like this for unsafe methods by default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed the default so guess it is ok now
|
||
* which implementation to use. `auto` will use `DefaultHttpRequestRetryHandler.INSTANCE`. | ||
* `default` will use a new instance of `DefaultHttpRequestRetryHandler` respecting `requestSentEnabled`, `count` and `nonRetryableClasses`. | ||
* `standard` will use an instance of `StandardHttpRequestRetryHandler` which assumes that all requested HTTP methods which should be idempotent according to RFC-2616 are in fact idempotent and can be retried. According to RFC-2616 section 9.1.2 the idempotent HTTP methods are: GET, HEAD, PUT, DELETE, OPTIONS, and TRACE. This implementation respects `requestSentEnabled` and `count`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's "RFC xyz". No hyphen involved.
|
||
* which implementation to use. `auto` will use `DefaultHttpRequestRetryHandler.INSTANCE`. | ||
* `default` will use a new instance of `DefaultHttpRequestRetryHandler` respecting `requestSentEnabled`, `count` and `nonRetryableClasses`. | ||
* `standard` will use an instance of `StandardHttpRequestRetryHandler` which assumes that all requested HTTP methods which should be idempotent according to RFC-2616 are in fact idempotent and can be retried. According to RFC-2616 section 9.1.2 the idempotent HTTP methods are: GET, HEAD, PUT, DELETE, OPTIONS, and TRACE. This implementation respects `requestSentEnabled` and `count`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't repeat the same as the Javadoc of that class. Simply link to it.
@Override | ||
public void run() | ||
{ | ||
final HttpRequestRetryHandler handler = getCurrentHttpClient(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is weird that getCurrentHttpClient()
does not return a client actually.
{ | ||
final Field nonRetriableClasses = handler.getClass().getSuperclass() | ||
.getDeclaredField( "nonRetriableClasses" ); | ||
if (!nonRetriableClasses.isAccessible()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this work with Java 10/11?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If modules are opened I think so
6f68473
to
ce7802e
Compare
Updated the PR accordingly the comments, let me know if it is better this way for you |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am still not convinced by stanard/default. From user perspective we have default
and standard
, what? Isn't it the same? What we have to provide has to be idiotsafe, idempotent. I currently trying to figure out what the benefit of the default
is and if whether standard
will cover 95% of all cases. The user still can provide a custom implementation.
|
||
[] | ||
|
||
Since version 3.0.1, the retry handler can be configured as well with system properties: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Version seems wrong
|
||
* <<<maven.wagon.http.retryhandler.class>>> supports this set of values: | ||
|
||
* which implementation to use. `auto` will use `DefaultHttpRequestRetryHandler.INSTANCE`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't auto gone?
* <<<maven.wagon.http.retryhandler.count>>> = number of retries for `default` or `standard` implementations. | ||
|
||
* <<<maven.wagon.http.retryhandler.nonRetryableClasses>>> = the comma separated list of classes bypassing the retries (only the `default` implementation). | ||
Default being `java.io.InterruptedIOException,java.io.UnknownHostException,java.io.ConnectException,java.io.SSLException` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no default anymore provided by us.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated the doc
Waiting for all spots to be resolved and a JIRA issue. Will then review, test and merge. |
@michael-o added a jira, think I adressed the issues, please let me know if I missed some |
You completely missed my review request:
|
@michael-o oh oki. Yes it makes sense, it basically exposes the known impl of httpclient in maven and match the same use cases. Rational was to never require a custom impl in 99% of the cases cause it is quite impacting to do it compared to configuring the standard or default impls. |
Alright, I will have at this later this day. I think there is still room for some improvement, but I like the big picture so far. |
* Comma separated list of non retryable classes. | ||
* Note: only used for default retry handler. | ||
* | ||
* @since 3.0.1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still wrong.
}; | ||
case "standard": | ||
return new StandardHttpRequestRetryHandler( RETRY_HANDLER_COUNT, RETRY_HANDLER_REQUEST_SENT_ENABLED ); | ||
case "auto": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be dropped completely.
@@ -354,6 +360,92 @@ private static PoolingHttpClientConnectionManager createConnManager() | |||
return connManager; | |||
} | |||
|
|||
/** | |||
* The type of the retry handler, default to DefaultHttpRequestRetryHandler. | |||
* Values can be default, standard (StandardHttpRequestRetryHandler), or a fully qualified name class. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is inconsistent in style. Please use: label
(class name
), or a fully qualified class name.
System.getProperty( "maven.wagon.http.retryhandler.class", "standard" ); | ||
|
||
/** | ||
* true if it's OK to retry non-idempotent requests that have been sent. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This statement is not true. The original documentation does not say this. Even the default implementation will stop before this value is read if the request ist not idempotent.
switch ( RETRY_HANDLER_CLASS ) | ||
{ | ||
case "default": | ||
if ( RETRY_HANDLER_EXCEPTIONS == null ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather rely on StringUtils#isEmpty()
.
final URLClassLoader loader = new URLClassLoader( urls.toArray( new URL[paths.length ] ) , new ClassLoader() | ||
{ | ||
@Override | ||
protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spaces missing
{ | ||
if ( name.startsWith( "org.apache.maven.wagon.shared.http" ) ) | ||
{ | ||
throw new ClassNotFoundException(name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
space missing
{ | ||
throw new ClassNotFoundException(name); | ||
} | ||
return super.loadClass(name, resolve); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
space missing
}); | ||
final Thread thread = Thread.currentThread(); | ||
final ClassLoader contextClassLoader = thread.getContextClassLoader(); | ||
thread.setContextClassLoader(loader); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
space missing
finally | ||
{ | ||
loader.close(); | ||
thread.setContextClassLoader(contextClassLoader); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
space missing
Looks very good now. I run push a test branch later this day. |
I have pushed a cleaned up branch. Please have a look. If all is fine, I will merge. |
@michael-o it is perfect, thanks a lot! |
No description provided.