From 26331d1a2c32d2c0fbccdf1742b4e178c8f68865 Mon Sep 17 00:00:00 2001 From: Dmitrii Priporov Date: Tue, 10 Jul 2018 22:05:01 +0300 Subject: [PATCH] Return HTTP status code 504 for Hystrix timeout in Zuul proxy (issue 2965) (#3060) * Fixes gh-2965 --- .../zuul/filters/post/SendErrorFilter.java | 16 +++++++++++++++- .../support/RibbonRetryIntegrationTestBase.java | 4 ++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/post/SendErrorFilter.java b/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/post/SendErrorFilter.java index a7063b307..12e72297b 100644 --- a/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/post/SendErrorFilter.java +++ b/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/filters/post/SendErrorFilter.java @@ -19,6 +19,7 @@ package org.springframework.cloud.netflix.zuul.filters.post; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; +import com.netflix.client.ClientException; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; @@ -31,6 +32,8 @@ import org.springframework.http.HttpStatus; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; +import java.net.SocketTimeoutException; + import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.ERROR_TYPE; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_ERROR_FILTER_ORDER; @@ -100,12 +103,23 @@ public class SendErrorFilter extends ZuulFilter { protected ExceptionHolder findZuulException(Throwable throwable) { if (throwable.getCause() instanceof ZuulRuntimeException) { + Throwable cause = null; + if (throwable.getCause().getCause() != null) { + cause = throwable.getCause().getCause().getCause(); + } + if (cause instanceof ClientException && cause.getCause() != null + && cause.getCause().getCause() instanceof SocketTimeoutException) { + + ZuulException zuulException = new ZuulException("", 504, + ZuulException.class.getName() + ": Hystrix Readed time out"); + return new ZuulExceptionHolder(zuulException); + } // this was a failure initiated by one of the local filters if(throwable.getCause().getCause() instanceof ZuulException) { return new ZuulExceptionHolder((ZuulException) throwable.getCause().getCause()); } } - + if (throwable.getCause() instanceof ZuulException) { // wrapped zuul exception return new ZuulExceptionHolder((ZuulException) throwable.getCause()); diff --git a/spring-cloud-netflix-zuul/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/support/RibbonRetryIntegrationTestBase.java b/spring-cloud-netflix-zuul/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/support/RibbonRetryIntegrationTestBase.java index 32dfca60c..ab2cefbeb 100644 --- a/spring-cloud-netflix-zuul/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/support/RibbonRetryIntegrationTestBase.java +++ b/spring-cloud-netflix-zuul/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/support/RibbonRetryIntegrationTestBase.java @@ -124,7 +124,7 @@ public abstract class RibbonRetryIntegrationTestBase { "http://localhost:" + this.port + uri, HttpMethod.GET, new HttpEntity<>((Void) null), String.class); LOG.info("Response Body: " + result.getBody()); - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, result.getStatusCode()); + assertEquals(HttpStatus.GATEWAY_TIMEOUT, result.getStatusCode()); } @Test @@ -134,7 +134,7 @@ public abstract class RibbonRetryIntegrationTestBase { "http://localhost:" + this.port + uri, HttpMethod.GET, new HttpEntity<>((Void) null), String.class); LOG.info("Response Body: " + result.getBody()); - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, result.getStatusCode()); + assertEquals(HttpStatus.GATEWAY_TIMEOUT, result.getStatusCode()); } // Don't use @SpringBootApplication because we don't want to component scan