Objetivo
O Spring Cloud Gateway está configurado com um timeout de disjuntor (circuit breaker):
# hystrix - timeout automático após 10 segundos
hystrix.command.fallbackCmd.execution.isolation.thread.timeoutInMilliseconds=10000
Quando ocorre um timeout, a lógica configurada no fallbackUri é executada. Existe a necessidade de retornar informações detalhadas sobre o "timeout da solicitação" em vez de uma mensagem genérica de "serviço indispnoível". Para isso, é preciso obter a exceção detalhada dentro desse método.
Aálise do Código Fonte
Analisando o método org.springframework.cloud.gateway.filter.factory.HystrixGatewayFilterFactory.RouteHystrixCommand#resumeWithFallback:
@Override
protected Observable<Void> resumeWithFallback() {
if (this.fallbackUri == null) {
return super.resumeWithFallback();
}
// TODO: copied from RouteToRequestUrlFilter
URI uri = exchange.getRequest().getURI();
// TODO: assume always?
boolean encoded = containsEncodedParts(uri);
URI requestUrl = UriComponentsBuilder.fromUri(uri).host(null).port(null)
.uri(this.fallbackUri).scheme(null).build(encoded).toUri();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
addExceptionDetails();
ServerHttpRequest request = this.exchange.getRequest().mutate()
.uri(requestUrl).build();
ServerWebExchange mutated = exchange.mutate().request(request).build();
// Before we continue on remove the already routed attribute since the
// fallback may go back through the route handler if the fallback
// is to another route in the Gateway
removeAlreadyRouted(mutated);
return RxReactiveStreams.toObservable(getDispatcherHandler().handle(mutated));
}
É possível observar que o HystrixGatewayFilter, ao processar a lógica de fallback, armazena as informações da exceção nos atributos do exchange através do atributo org.springframework.cloud.gateway.support.ServerWebExchangeUtils#GATEWAY_REQUEST_URL_ATTR. Portanto, basta recuperar esses detalhes diretamente no controller.
Exemplo Prático
@Log4j2
@RestController
public class HystrixFallbackController {
/**
* Tratamento de degradação de serviço
*
* @return ResponseVO
*/
@RequestMapping("/defaultFallback")
public ResponseVO<Void> handleFallback(ServerWebExchange exchange) {
log.warn("Degradação de serviço...{}", Objects.toString(
exchange.getAttribute(ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR)));
Exception ex = exchange.getAttribute(ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR);
if (ex instanceof HystrixTimeoutException) {
return ResponseFactory.errorResponseFromMsg("Timeout na solicitação do gateway...");
}
return ResponseFactory.errorResponseFromMsg("Serviço temporariamente indisponível, tente novamente mais tarde...");
}
}