diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java index 7852ef5e..68161d2b 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java @@ -121,7 +121,10 @@ public class RetryGatewayFilterFactory Retry exceptionRetry = null; if (!retryConfig.getExceptions().isEmpty()) { Predicate> retryContextPredicate = context -> { - if (exceedsMaxIterations(context.applicationContext(), retryConfig)) { + + ServerWebExchange exchange = context.applicationContext(); + + if (exceedsMaxIterations(exchange, retryConfig)) { return false; } @@ -133,7 +136,14 @@ public class RetryGatewayFilterFactory trace("exception or its cause is retryable %s, configured exceptions %s", () -> getExceptionNameWithCause(exception), retryConfig::getExceptions); - return true; + + HttpMethod httpMethod = exchange.getRequest().getMethod(); + boolean retryableMethod = retryConfig.getMethods() + .contains(httpMethod); + trace("retryableMethod: %b, httpMethod %s, configured methods %s", + () -> retryableMethod, () -> httpMethod, + retryConfig::getMethods); + return retryableMethod; } } trace("exception or its cause is not retryable %s, configured exceptions %s", diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java index 98c006b5..1ca17cf3 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java @@ -147,6 +147,27 @@ public class RetryGatewayFilterFactoryIntegrationTests extends BaseWebClientTest assertThat(TestConfig.map.get("sleepyRequest")).isNotNull().hasValue(3); } + @Test + public void shouldNotRetryWhenSleepyRequestPost() throws Exception { + testClient.mutate().responseTimeout(Duration.ofSeconds(10)).build().post() + .uri("/sleep?key=notRetriesSleepyRequestPost&millis=3000") + .header(HttpHeaders.HOST, "www.retry-only-get.org").exchange() + .expectStatus().isEqualTo(HttpStatus.GATEWAY_TIMEOUT); + + assertThat(TestConfig.map.get("notRetriesSleepyRequestPost")).isNotNull() + .hasValue(1); + } + + @Test + public void shouldRetryWhenSleepyRequestGet() throws Exception { + testClient.mutate().responseTimeout(Duration.ofSeconds(10)).build().get() + .uri("/sleep?key=sleepyRequestGet&millis=3000") + .header(HttpHeaders.HOST, "www.retry-only-get.org").exchange() + .expectStatus().isEqualTo(HttpStatus.GATEWAY_TIMEOUT); + + assertThat(TestConfig.map.get("sleepyRequestGet")).isNotNull().hasValue(3); + } + @Test @SuppressWarnings("unchecked") public void retryFilterLoadBalancedWithMultipleServers() { @@ -252,7 +273,11 @@ public class RetryGatewayFilterFactoryIntegrationTests extends BaseWebClientTest .retry(config -> config.setRetries(2) .setMethods(HttpMethod.POST, HttpMethod.GET))) .uri(uri)) - + .route("retry_only_get", r -> r.host("**.retry-only-get.org") + .filters(f -> f.prefixPath("/httpbin") + .retry(config -> config.setRetries(2) + .setMethods(HttpMethod.GET))) + .uri(uri)) .route("retry_with_backoff", r -> r.host("**.retrywithbackoff.org") .filters(f -> f.prefixPath("/httpbin").retry(config -> { config.setRetries(2).setBackoff(Duration.ofMillis(100),