In case the failureType coming from Hystrix is SHOSRTCIRCUIT, then HTTP 503 is dispatched (#1230)

* In case the failureType coming from Hystrix is SHOSRTCIRCUIT, then
ServiceUnavailableException will be thrown. That exception provides HTTP
503 to the original service consumer.
Moreover, HystrixGatewayFilterFactoryTests have been enriched so that
the aforementioned case is tested and verified.

* The hystrixFilterServiceUnavailable test of
HystrixGatewayFilterFactoryTests no longer force-closes the circuit in
order not to impact any subsequent tests (see also the comment:
https://github.com/spring-cloud/spring-cloud-gateway/pull/1230#pullrequestreview-272440126)
This commit is contained in:
gminog
2019-08-13 10:35:15 +00:00
committed by Olga Maciaszek-Sharma
parent f17cf9e1ad
commit b11fd5b2f9
3 changed files with 64 additions and 0 deletions

View File

@@ -34,6 +34,7 @@ import rx.Subscription;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.support.ServiceUnavailableException;
import org.springframework.cloud.gateway.support.TimeoutException;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
@@ -134,6 +135,8 @@ public class HystrixGatewayFilterFactory
switch (failureType) {
case TIMEOUT:
return Mono.error(new TimeoutException());
case SHORTCIRCUIT:
return Mono.error(new ServiceUnavailableException());
case COMMAND_EXCEPTION: {
Throwable cause = e.getCause();

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed 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
*
* https://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.
*/
package org.springframework.cloud.gateway.support;
import org.springframework.web.bind.annotation.ResponseStatus;
import static org.springframework.http.HttpStatus.SERVICE_UNAVAILABLE;
@ResponseStatus(value = SERVICE_UNAVAILABLE, reason = "Upstream service is temporarily unavailable")
public class ServiceUnavailableException extends Exception {
public ServiceUnavailableException() {
}
public ServiceUnavailableException(String message) {
super(message);
}
/**
* Disables fillInStackTrace for performance reasons.
* @return
*/
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}

View File

@@ -16,6 +16,9 @@
package org.springframework.cloud.gateway.filter.factory;
import com.netflix.config.ConfigurationManager;
import com.netflix.hystrix.Hystrix;
import com.netflix.hystrix.metric.consumer.HealthCountsStream;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -56,6 +59,22 @@ public class HystrixGatewayFilterFactoryTests extends BaseWebClientTests {
.isEqualTo(String.valueOf(HttpStatus.GATEWAY_TIMEOUT.value()));
}
@Test
public void hystrixFilterServiceUnavailable() {
HealthCountsStream.reset();
Hystrix.reset();
ConfigurationManager.getConfigInstance()
.setProperty("hystrix.command.failcmd.circuitBreaker.forceOpen", true);
testClient.get().uri("/delay/3").header("Host", "www.hystrixfailure.org")
.exchange().expectStatus().isEqualTo(HttpStatus.SERVICE_UNAVAILABLE);
HealthCountsStream.reset();
Hystrix.reset();
ConfigurationManager.getConfigInstance()
.setProperty("hystrix.command.failcmd.circuitBreaker.forceOpen", false);
}
/*
* Tests that timeouts bubbling from the underpinning WebClient are treated the same
* as Hystrix timeouts in terms of outside response. (Internally, timeouts from the