From 2d86f4451f1aaf719e224a56a4491372614c1ec2 Mon Sep 17 00:00:00 2001 From: Sebastian Lohmeier Date: Mon, 4 Sep 2023 22:03:05 +0200 Subject: [PATCH] feat: Retry all http methods --- .../com/dius/pact/core/support/HttpClient.kt | 10 +++++++- .../pact/core/support/HttpClientSpec.groovy | 25 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/core/support/src/main/kotlin/au/com/dius/pact/core/support/HttpClient.kt b/core/support/src/main/kotlin/au/com/dius/pact/core/support/HttpClient.kt index d819fbe1e0..6367e59373 100644 --- a/core/support/src/main/kotlin/au/com/dius/pact/core/support/HttpClient.kt +++ b/core/support/src/main/kotlin/au/com/dius/pact/core/support/HttpClient.kt @@ -18,6 +18,7 @@ import org.apache.hc.client5.http.socket.ConnectionSocketFactory import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder import org.apache.hc.client5.http.ssl.TrustSelfSignedStrategy +import org.apache.hc.core5.http.HttpRequest import org.apache.hc.core5.http.config.RegistryBuilder import org.apache.hc.core5.http.message.BasicHeader import org.apache.hc.core5.ssl.SSLContexts @@ -70,6 +71,13 @@ sealed class Auth { } } +private class RetryAnyMethod( + maxRetries: Int, + defaultRetryInterval: TimeValue +): DefaultHttpRequestRetryStrategy(maxRetries, defaultRetryInterval) { + override fun handleAsIdempotent(request: HttpRequest) = true +} + /** * HTTP client support functions */ @@ -86,7 +94,7 @@ object HttpClient : KLogging() { insecureTLS: Boolean = false ): Pair { val builder = HttpClients.custom().useSystemProperties() - .setRetryStrategy(DefaultHttpRequestRetryStrategy(maxPublishRetries, + .setRetryStrategy(RetryAnyMethod(maxPublishRetries, TimeValue.ofMilliseconds(publishRetryInterval.toLong()))) val defaultHeaders = mutableMapOf() diff --git a/core/support/src/test/groovy/au/com/dius/pact/core/support/HttpClientSpec.groovy b/core/support/src/test/groovy/au/com/dius/pact/core/support/HttpClientSpec.groovy index 59d63848af..b507756630 100644 --- a/core/support/src/test/groovy/au/com/dius/pact/core/support/HttpClientSpec.groovy +++ b/core/support/src/test/groovy/au/com/dius/pact/core/support/HttpClientSpec.groovy @@ -1,7 +1,10 @@ package au.com.dius.pact.core.support +import org.apache.hc.client5.http.impl.classic.HttpRequestRetryExec import org.apache.hc.client5.http.impl.classic.ProtocolExec import org.apache.hc.client5.http.protocol.RequestDefaultHeaders +import org.apache.hc.core5.http.HttpRequest +import org.apache.hc.core5.http.Method import spock.lang.Specification class HttpClientSpec extends Specification { @@ -30,4 +33,26 @@ class HttpClientSpec extends Specification { defaultHeaders[0].name == 'Authorization' defaultHeaders[0].value == 'Bearer 1234abcd' } + + def 'http client should retry any requests for any method'(Method method) { + def uri = new URI('http://localhost') + def request = Mock(HttpRequest) + request.method >> method + def client = HttpClient.INSTANCE.newHttpClient(null, uri, 1, 1, false).component1() + def retryStrategy = null + def execChain = client.execChain + while (retryStrategy == null && execChain != null) { + if (execChain.handler instanceof HttpRequestRetryExec) { + retryStrategy = execChain.handler.retryStrategy + } else { + execChain = execChain.next + } + } + + expect: + retryStrategy.handleAsIdempotent(request) == true + + where: + method << Method.values() + } }