WeightCalculatorWebFilter now forces subscription of RouteLocator.
Because it needs to calculate the weights before predicates run, if the predicates are all defined in yaml, weights aren't initialized until after the first run, meaning weights are unavailable in the predicates. WeightCalculatorWebFilter now listens for RoutesRefreshedEvent. When triggered, it subscribes to RouteLocator, forcing initialization. fixes gh-332
This commit is contained in:
@@ -392,8 +392,8 @@ public class GatewayAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WeightCalculatorWebFilter weightCalculatorWebFilter(Validator validator) {
|
||||
return new WeightCalculatorWebFilter(validator);
|
||||
public WeightCalculatorWebFilter weightCalculatorWebFilter(Validator validator, ObjectProvider<RouteLocator> routeLocator) {
|
||||
return new WeightCalculatorWebFilter(validator, routeLocator);
|
||||
}
|
||||
|
||||
/*@Bean
|
||||
|
||||
@@ -27,9 +27,13 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.cloud.gateway.event.PredicateArgsEvent;
|
||||
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
|
||||
import org.springframework.cloud.gateway.event.WeightDefinedEvent;
|
||||
import org.springframework.cloud.gateway.route.RouteLocator;
|
||||
import org.springframework.cloud.gateway.support.ConfigurationUtils;
|
||||
import org.springframework.cloud.gateway.support.WeightConfig;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
@@ -43,8 +47,6 @@ import org.springframework.web.server.WebFilterChain;
|
||||
|
||||
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.WEIGHT_ATTR;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@@ -55,17 +57,24 @@ public class WeightCalculatorWebFilter implements WebFilter, Ordered, SmartAppli
|
||||
public static final int WEIGHT_CALC_FILTER_ORDER = 10001;
|
||||
|
||||
private final Validator validator;
|
||||
private final ObjectProvider<RouteLocator> routeLocator;
|
||||
private Random random = new Random();
|
||||
private int order = WEIGHT_CALC_FILTER_ORDER;
|
||||
|
||||
private Map<String, GroupWeightConfig> groupWeights = new ConcurrentHashMap<>();
|
||||
|
||||
/* for testing */ WeightCalculatorWebFilter() {
|
||||
this(null);
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public WeightCalculatorWebFilter(Validator validator) {
|
||||
this(validator, null);
|
||||
}
|
||||
|
||||
public WeightCalculatorWebFilter(Validator validator, ObjectProvider<RouteLocator> routeLocator) {
|
||||
this.validator = validator;
|
||||
this.routeLocator = routeLocator;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,7 +93,8 @@ public class WeightCalculatorWebFilter implements WebFilter, Ordered, SmartAppli
|
||||
@Override
|
||||
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
|
||||
return PredicateArgsEvent.class.isAssignableFrom(eventType) || // config file
|
||||
WeightDefinedEvent.class.isAssignableFrom(eventType); // java dsl
|
||||
WeightDefinedEvent.class.isAssignableFrom(eventType) || // java dsl
|
||||
RefreshRoutesEvent.class.isAssignableFrom(eventType); // force initialization
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,6 +108,8 @@ public class WeightCalculatorWebFilter implements WebFilter, Ordered, SmartAppli
|
||||
handle((PredicateArgsEvent) event);
|
||||
} else if (event instanceof WeightDefinedEvent) {
|
||||
addWeightConfig(((WeightDefinedEvent)event).getWeightConfig());
|
||||
} else if (event instanceof RefreshRoutesEvent && routeLocator != null) {
|
||||
routeLocator.ifAvailable(locator -> locator.getRoutes().subscribe()); // forces initialization
|
||||
}
|
||||
|
||||
}
|
||||
@@ -197,7 +209,6 @@ public class WeightCalculatorWebFilter implements WebFilter, Ordered, SmartAppli
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/* for testing */ static Map<String, String> getWeights(ServerWebExchange exchange) {
|
||||
Map<String, String> weights = exchange.getAttribute(WEIGHT_ATTR);
|
||||
|
||||
|
||||
@@ -92,6 +92,8 @@ public class WeightRoutePredicateFactory extends AbstractRoutePredicateFactory<W
|
||||
}
|
||||
|
||||
return routeId.equals(chosenRoute);
|
||||
} else if (log.isTraceEnabled()) {
|
||||
log.trace("no weights found for group: "+ group + ", current route: " + routeId);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.handler.predicate;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter;
|
||||
import org.springframework.cloud.gateway.test.BaseWebClientTests;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = RANDOM_PORT)
|
||||
@ActiveProfiles("weights-404")
|
||||
@DirtiesContext
|
||||
public class WeightRoutePredicateFactoryYaml404Tests extends BaseWebClientTests {
|
||||
|
||||
@Autowired
|
||||
private WeightCalculatorWebFilter filter;
|
||||
|
||||
@Test
|
||||
public void weightsFromYamlNot404() {
|
||||
filter.setRandom(getRandom(0.5));
|
||||
|
||||
testClient.get().uri("/get")
|
||||
.header(HttpHeaders.HOST, "www.weight4041.org")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().valueEquals(ROUTE_ID_HEADER, "weight_first_404_test_1");
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@SpringBootConfiguration
|
||||
@Import(DefaultTestConfig.class)
|
||||
public static class TestConfig {
|
||||
|
||||
public TestConfig(WeightCalculatorWebFilter filter) {
|
||||
Random random = getRandom(0.4);
|
||||
|
||||
filter.setRandom(random);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Random getRandom(double value) {
|
||||
Random random = mock(Random.class);
|
||||
when(random.nextDouble())
|
||||
.thenReturn(value);
|
||||
return random;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
test:
|
||||
uri: lb://testservice
|
||||
|
||||
spring:
|
||||
cloud:
|
||||
gateway:
|
||||
default-filters:
|
||||
- PrefixPath=/httpbin
|
||||
routes:
|
||||
# =====================================
|
||||
- id: weight_first_404_test_1
|
||||
uri: ${test.uri}
|
||||
predicates:
|
||||
- Host=**.weight4041.org
|
||||
- Weight=group404, 8
|
||||
|
||||
# =====================================
|
||||
- id: weight_first_404_test_2
|
||||
uri: ${test.uri}
|
||||
predicates:
|
||||
- Host=**.weight4042.org
|
||||
- Weight=group404, 2
|
||||
Reference in New Issue
Block a user