You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by mi...@apache.org on 2019/10/29 20:49:55 UTC
[maven-wagon] branch WAGON-567 created (now 49c3537)
This is an automated email from the ASF dual-hosted git repository.
michaelo pushed a change to branch WAGON-567
in repository https://gitbox.apache.org/repos/asf/maven-wagon.git.
at 49c3537 [WAGON-567] Provide request retry strategy on transient client and server side errors
This branch includes the following new commits:
new 49c3537 [WAGON-567] Provide request retry strategy on transient client and server side errors
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[maven-wagon] 01/01: [WAGON-567] Provide request retry strategy on
transient client and server side errors
Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
michaelo pushed a commit to branch WAGON-567
in repository https://gitbox.apache.org/repos/asf/maven-wagon.git
commit 49c3537e1e1541538013c376e5ac57b09a3ec230
Author: Chandler Zhang <xz...@atlassian.com>
AuthorDate: Tue Oct 22 13:50:45 2019 +1100
[WAGON-567] Provide request retry strategy on transient client and server side errors
This closes #57
---
.../wagon/shared/http/AbstractHttpClientWagon.java | 52 ++++++++++++++
.../StandardServiceUnavailableRetryStrategy.java | 79 ++++++++++++++++++++++
2 files changed, 131 insertions(+)
diff --git a/wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java b/wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java
index 7fcbc7f..3bf4291 100755
--- a/wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java
+++ b/wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java
@@ -34,6 +34,7 @@ import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpRequestRetryHandler;
+import org.apache.http.client.ServiceUnavailableRetryStrategy;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
@@ -61,6 +62,7 @@ import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
+import org.apache.http.impl.client.DefaultServiceUnavailableRetryStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.StandardHttpRequestRetryHandler;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
@@ -456,6 +458,55 @@ public abstract class AbstractHttpClientWagon
}
}
+ /**
+ * The type of the serviceUnavailableRetryStrategy, defaults to {@code none}.
+ * Values can be {@link default DefaultServiceUnavailableRetryStrategy},
+ * or {@link standard StandardServiceUnavailableRetryStrategy}, or
+ * a fully qualified name class with a no-arg or none to not use a ServiceUnavailableRetryStrategy.
+ */
+ private static final String SERVICE_UNAVAILABLE_RETRY_STRATEGY_CLASS =
+ System.getProperty( "maven.wagon.http.serviceUnavailableRetryStrategy.class", "none" );
+
+ /**
+ * Interval in milliseconds between retries when using a serviceUnavailableRetryStrategy.
+ * <b>1000 by default</b>
+ */
+ private static final int SERVICE_UNAVAILABLE_RETRY_STRATEGY_RETRY_INTERVAL =
+ Integer.getInteger( "maven.wagon.http.serviceUnavailableRetryStrategy.retryInterval", 1000 );
+
+ /**
+ * Maximum number of retries when using a serviceUnavailableRetryStrategy.
+ * <b>5 by default</b>
+ */
+ private static final int SERVICE_UNAVAILABLE_RETRY_STRATEGY_MAX_RETRIES =
+ Integer.getInteger( "maven.wagon.http.serviceUnavailableRetryStrategy.maxRetries", 5 );
+
+ private static ServiceUnavailableRetryStrategy createServiceUnavailableRetryStrategy()
+ {
+ switch ( SERVICE_UNAVAILABLE_RETRY_STRATEGY_CLASS )
+ {
+ case "none": return null;
+ case "default":
+ return new DefaultServiceUnavailableRetryStrategy(
+ SERVICE_UNAVAILABLE_RETRY_STRATEGY_MAX_RETRIES, SERVICE_UNAVAILABLE_RETRY_STRATEGY_RETRY_INTERVAL );
+ case "standard":
+ return new StandardServiceUnavailableRetryStrategy(
+ SERVICE_UNAVAILABLE_RETRY_STRATEGY_MAX_RETRIES, SERVICE_UNAVAILABLE_RETRY_STRATEGY_RETRY_INTERVAL );
+ default:
+ try
+ {
+ final ClassLoader classLoader = AbstractHttpClientWagon.class.getClassLoader();
+ return ServiceUnavailableRetryStrategy.class.cast(
+ classLoader.loadClass( SERVICE_UNAVAILABLE_RETRY_STRATEGY_CLASS )
+ .getConstructor().newInstance() );
+ }
+ catch ( final Exception e )
+ {
+ throw new IllegalArgumentException( e );
+ }
+ }
+ }
+
private static Registry<AuthSchemeProvider> createAuthSchemeRegistry()
{
return RegistryBuilder.<AuthSchemeProvider>create()
@@ -492,6 +543,7 @@ public abstract class AbstractHttpClientWagon
.disableConnectionState() //
.setConnectionManager( httpClientConnectionManager ) //
.setRetryHandler( createRetryHandler() )
+ .setServiceUnavailableRetryStrategy( createServiceUnavailableRetryStrategy() )
.setDefaultAuthSchemeRegistry( createAuthSchemeRegistry() )
.build();
}
diff --git a/wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/StandardServiceUnavailableRetryStrategy.java b/wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/StandardServiceUnavailableRetryStrategy.java
new file mode 100644
index 0000000..7f4d485
--- /dev/null
+++ b/wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/StandardServiceUnavailableRetryStrategy.java
@@ -0,0 +1,79 @@
+package org.apache.maven.wagon.shared.http;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.annotation.Contract;
+import org.apache.http.annotation.ThreadingBehavior;
+import org.apache.http.client.ServiceUnavailableRetryStrategy;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.Args;
+
+/**
+ * An implementation of the {@link ServiceUnavailableRetryStrategy} interface.
+ * that retries {@code 408} (Request Timeout), {@code 429} (Too Many Requests),
+ * and {@code 500} (Server side error) responses for a fixed number of times at a fixed interval.
+ */
+@Contract( threading = ThreadingBehavior.IMMUTABLE )
+public class StandardServiceUnavailableRetryStrategy implements ServiceUnavailableRetryStrategy
+{
+ /**
+ * Maximum number of allowed retries if the server responds with a HTTP code
+ * in our retry code list.
+ */
+ private final int maxRetries;
+
+ /**
+ * Retry interval between subsequent requests, in milliseconds.
+ */
+ private final long retryInterval;
+
+ public StandardServiceUnavailableRetryStrategy( final int maxRetries, final int retryInterval )
+ {
+ super();
+ Args.positive( maxRetries, "Max retries" );
+ Args.positive( retryInterval, "Retry interval" );
+ this.maxRetries = maxRetries;
+ this.retryInterval = retryInterval;
+ }
+
+ @Override
+ public boolean retryRequest( final HttpResponse response, final int executionCount, final HttpContext context )
+ {
+ int statusCode = response.getStatusLine().getStatusCode();
+ boolean retryableStatusCode = statusCode == HttpStatus.SC_REQUEST_TIMEOUT
+ // Too Many Requests ("standard" rate-limiting)
+ || statusCode == AbstractHttpClientWagon.SC_TOO_MANY_REQUESTS
+ // Assume server errors are momentary hiccups
+ || statusCode == HttpStatus.SC_INTERNAL_SERVER_ERROR
+ || statusCode == HttpStatus.SC_BAD_GATEWAY
+ || statusCode == HttpStatus.SC_SERVICE_UNAVAILABLE
+ || statusCode == HttpStatus.SC_GATEWAY_TIMEOUT;
+ return executionCount <= maxRetries && retryableStatusCode;
+ }
+
+ @Override
+ public long getRetryInterval()
+ {
+ return retryInterval;
+ }
+
+}