|
|
@ -19,6 +19,7 @@ package com.tencent.cloud.polaris.circuitbreaker.gateway;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import java.net.URI;
|
|
|
|
import java.net.URI;
|
|
|
|
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.List;
|
|
|
@ -26,9 +27,9 @@ import java.util.Objects;
|
|
|
|
import java.util.Set;
|
|
|
|
import java.util.Set;
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import com.tencent.polaris.api.pojo.CircuitBreakerStatus;
|
|
|
|
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
|
|
|
|
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import reactor.core.publisher.Flux;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
import reactor.core.publisher.Mono;
|
|
|
|
import reactor.core.publisher.Mono;
|
|
|
|
|
|
|
|
|
|
|
|
import org.springframework.beans.InvalidPropertyException;
|
|
|
|
import org.springframework.beans.InvalidPropertyException;
|
|
|
@ -42,8 +43,11 @@ import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
|
|
|
import org.springframework.cloud.gateway.filter.factory.SpringCloudCircuitBreakerFilterFactory;
|
|
|
|
import org.springframework.cloud.gateway.filter.factory.SpringCloudCircuitBreakerFilterFactory;
|
|
|
|
import org.springframework.cloud.gateway.support.HttpStatusHolder;
|
|
|
|
import org.springframework.cloud.gateway.support.HttpStatusHolder;
|
|
|
|
import org.springframework.cloud.gateway.support.ServiceUnavailableException;
|
|
|
|
import org.springframework.cloud.gateway.support.ServiceUnavailableException;
|
|
|
|
|
|
|
|
import org.springframework.core.io.buffer.DataBuffer;
|
|
|
|
import org.springframework.http.HttpStatus;
|
|
|
|
import org.springframework.http.HttpStatus;
|
|
|
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
|
|
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
|
|
|
|
|
|
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
|
|
|
|
|
|
|
import org.springframework.util.CollectionUtils;
|
|
|
|
import org.springframework.util.StringUtils;
|
|
|
|
import org.springframework.util.StringUtils;
|
|
|
|
import org.springframework.web.reactive.DispatcherHandler;
|
|
|
|
import org.springframework.web.reactive.DispatcherHandler;
|
|
|
|
import org.springframework.web.server.ResponseStatusException;
|
|
|
|
import org.springframework.web.server.ResponseStatusException;
|
|
|
@ -65,8 +69,6 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.r
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public class PolarisCircuitBreakerFilterFactory extends SpringCloudCircuitBreakerFilterFactory {
|
|
|
|
public class PolarisCircuitBreakerFilterFactory extends SpringCloudCircuitBreakerFilterFactory {
|
|
|
|
|
|
|
|
|
|
|
|
private static final Logger LOGGER = LoggerFactory.getLogger(PolarisCircuitBreakerFilterFactory.class);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private String routeIdPrefix;
|
|
|
|
private String routeIdPrefix;
|
|
|
|
|
|
|
|
|
|
|
|
private final ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory;
|
|
|
|
private final ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory;
|
|
|
@ -150,6 +152,12 @@ public class PolarisCircuitBreakerFilterFactory extends SpringCloudCircuitBreake
|
|
|
|
return Arrays.asList(allHttpStatus);
|
|
|
|
return Arrays.asList(allHttpStatus);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Set<HttpStatus> getDefaultStatus() {
|
|
|
|
|
|
|
|
return Arrays.stream(HttpStatus.values())
|
|
|
|
|
|
|
|
.filter(status -> status.is4xxClientError() || status.is5xxServerError())
|
|
|
|
|
|
|
|
.collect(Collectors.toSet());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public GatewayFilter apply(Config config) {
|
|
|
|
public GatewayFilter apply(Config config) {
|
|
|
|
Set<HttpStatus> statuses = config.getStatusCodes().stream()
|
|
|
|
Set<HttpStatus> statuses = config.getStatusCodes().stream()
|
|
|
@ -165,6 +173,9 @@ public class PolarisCircuitBreakerFilterFactory extends SpringCloudCircuitBreake
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.filter(Objects::nonNull)
|
|
|
|
.filter(Objects::nonNull)
|
|
|
|
.collect(Collectors.toSet());
|
|
|
|
.collect(Collectors.toSet());
|
|
|
|
|
|
|
|
if (CollectionUtils.isEmpty(statuses)) {
|
|
|
|
|
|
|
|
statuses.addAll(getDefaultStatus());
|
|
|
|
|
|
|
|
}
|
|
|
|
String circuitBreakerId = getCircuitBreakerId(config);
|
|
|
|
String circuitBreakerId = getCircuitBreakerId(config);
|
|
|
|
return new GatewayFilter() {
|
|
|
|
return new GatewayFilter() {
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
@ -178,6 +189,22 @@ public class PolarisCircuitBreakerFilterFactory extends SpringCloudCircuitBreake
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}), t -> {
|
|
|
|
}), t -> {
|
|
|
|
if (config.getFallbackUri() == null) {
|
|
|
|
if (config.getFallbackUri() == null) {
|
|
|
|
|
|
|
|
if (t instanceof CallAbortedException) {
|
|
|
|
|
|
|
|
CircuitBreakerStatus.FallbackInfo fallbackInfo = ((CallAbortedException) t).getFallbackInfo();
|
|
|
|
|
|
|
|
if (fallbackInfo != null) {
|
|
|
|
|
|
|
|
ServerHttpResponse response = exchange.getResponse();
|
|
|
|
|
|
|
|
response.setRawStatusCode(fallbackInfo.getCode());
|
|
|
|
|
|
|
|
if (fallbackInfo.getHeaders() != null) {
|
|
|
|
|
|
|
|
fallbackInfo.getHeaders().forEach((k, v) -> response.getHeaders().add(k, v));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fallbackInfo.getBody() != null) {
|
|
|
|
|
|
|
|
byte[] bytes = fallbackInfo.getBody().getBytes(StandardCharsets.UTF_8);
|
|
|
|
|
|
|
|
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
|
|
|
|
|
|
|
|
return exchange.getResponse().writeWith(Flux.just(buffer));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return chain.filter(exchange);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return Mono.error(t);
|
|
|
|
return Mono.error(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -216,7 +243,6 @@ public class PolarisCircuitBreakerFilterFactory extends SpringCloudCircuitBreake
|
|
|
|
return Mono.error(new ResponseStatusException(HttpStatus.GATEWAY_TIMEOUT, t.getMessage(), t));
|
|
|
|
return Mono.error(new ResponseStatusException(HttpStatus.GATEWAY_TIMEOUT, t.getMessage(), t));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (t instanceof CallAbortedException) {
|
|
|
|
if (t instanceof CallAbortedException) {
|
|
|
|
LOGGER.debug("PolarisCircuitBreaker CallAbortedException: {}", t.getMessage());
|
|
|
|
|
|
|
|
return Mono.error(new ServiceUnavailableException());
|
|
|
|
return Mono.error(new ServiceUnavailableException());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (resumeWithoutError) {
|
|
|
|
if (resumeWithoutError) {
|
|
|
|