Browse Source

Add hints to API via the Request interface. Fixes gh-647. (#669)

* Add hints to API via the Request interface. Fixes gh-647.

* Switch to generic context.
pull/683/head
Olga Maciaszek-Sharma 5 years ago committed by Spencer Gibb
parent
commit
ec784b757e
  1. 24
      spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/DefaultRequest.java
  2. 47
      spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/DefaultRequestContext.java
  3. 3
      spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/ReactiveLoadBalancer.java
  4. 8
      spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/Request.java
  5. 1
      spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/ReactorLoadBalancer.java
  6. 1
      spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/RoundRobinLoadBalancer.java
  7. 52
      spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/LoadBalancerTests.java

24
spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/DefaultRequest.java

@ -17,8 +17,30 @@ @@ -17,8 +17,30 @@
package org.springframework.cloud.client.loadbalancer.reactive;
/**
* A default implementation of {@link Request}.
*
* @author Spencer Gibb
* @author Olga Maciaszek-Sharma
*/
public class DefaultRequest implements Request {
public class DefaultRequest<T> implements Request<T> {
private T context;
public DefaultRequest() {
new DefaultRequestContext();
}
public DefaultRequest(T context) {
this.context = context;
}
@Override
public T getContext() {
return context;
}
public void setContext(T context) {
this.context = context;
}
}

47
spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/DefaultRequestContext.java

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
/*
* Copyright 2012-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.client.loadbalancer.reactive;
/**
* Contains information relevant to the request.
*
* @author Olga Maciaszek-Sharma
*/
public class DefaultRequestContext {
/**
* A {@link String} value of hint that can be used to choose the correct service
* instance.
*/
private String hint = "default";
public DefaultRequestContext() {
}
public DefaultRequestContext(String hint) {
this.hint = hint;
}
public String getHint() {
return hint;
}
public void setHint(String hint) {
this.hint = hint;
}
}

3
spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/ReactiveLoadBalancer.java

@ -30,13 +30,14 @@ public interface ReactiveLoadBalancer<T> { @@ -30,13 +30,14 @@ public interface ReactiveLoadBalancer<T> {
/**
* Default implementation of a request.
*/
Request REQUEST = new DefaultRequest();
Request<DefaultRequestContext> REQUEST = new DefaultRequest();
/**
* Choose the next server based on the load balancing algorithm.
* @param request - incoming request
* @return publisher for the response
*/
@SuppressWarnings("rawtypes")
Publisher<Response<T>> choose(Request request);
default Publisher<Response<T>> choose() { // conflicting name

8
spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/Request.java

@ -20,8 +20,14 @@ package org.springframework.cloud.client.loadbalancer.reactive; @@ -20,8 +20,14 @@ package org.springframework.cloud.client.loadbalancer.reactive;
* Marker interface for a request.
*
* @author Spencer Gibb
* @author Olga Maciaszek-Sharma
*/
public interface Request {
public interface Request<C> {
// Avoid breaking backward compatibility
default C getContext() {
return null;
}
// TODO: define contents

1
spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/ReactorLoadBalancer.java

@ -35,6 +35,7 @@ public interface ReactorLoadBalancer<T> extends ReactiveLoadBalancer<T> { @@ -35,6 +35,7 @@ public interface ReactorLoadBalancer<T> extends ReactiveLoadBalancer<T> {
* @param request - an input request
* @return - mono of response
*/
@SuppressWarnings("rawtypes")
Mono<Response<T>> choose(Request request);
default Mono<Response<T>> choose() {

1
spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/RoundRobinLoadBalancer.java

@ -104,6 +104,7 @@ public class RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalance @@ -104,6 +104,7 @@ public class RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalance
this.position = new AtomicInteger(seedPosition);
}
@SuppressWarnings("rawtypes")
@Override
// see original
// https://github.com/Netflix/ocelli/blob/master/ocelli-core/

52
spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/LoadBalancerTests.java

@ -24,6 +24,7 @@ import org.junit.runner.RunWith; @@ -24,6 +24,7 @@ import org.junit.runner.RunWith;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -33,7 +34,11 @@ import org.springframework.cloud.client.DefaultServiceInstance; @@ -33,7 +34,11 @@ import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.reactive.CompletionContext;
import org.springframework.cloud.client.loadbalancer.reactive.CompletionContext.Status;
import org.springframework.cloud.client.loadbalancer.reactive.DefaultRequest;
import org.springframework.cloud.client.loadbalancer.reactive.DefaultRequestContext;
import org.springframework.cloud.client.loadbalancer.reactive.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
import org.springframework.cloud.client.loadbalancer.reactive.Request;
import org.springframework.cloud.client.loadbalancer.reactive.Response;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
@ -45,6 +50,7 @@ import org.springframework.core.ResolvableType; @@ -45,6 +50,7 @@ import org.springframework.core.ResolvableType;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.BDDAssertions.then;
/**
@ -125,6 +131,11 @@ public class LoadBalancerTests { @@ -125,6 +131,11 @@ public class LoadBalancerTests {
assertLoadBalancer(loadBalancer, Arrays.asList("1host", "2host-secure"));
}
private static DefaultServiceInstance instance(String serviceId, String host,
boolean secure) {
return new DefaultServiceInstance(serviceId, serviceId, host, 80, secure);
}
@Test
public void staticConfigurationWorksWithServiceInstanceListSupplier() {
String serviceId = "test1";
@ -136,9 +147,44 @@ public class LoadBalancerTests { @@ -136,9 +147,44 @@ public class LoadBalancerTests {
assertLoadBalancer(loadBalancer, Arrays.asList("1host", "2host-secure"));
}
private DefaultServiceInstance instance(String serviceId, String host,
boolean secure) {
return new DefaultServiceInstance(serviceId, serviceId, host, 80, secure);
@SuppressWarnings("ConstantConditions")
@Test
public void canPassHintViaRequest() {
String serviceId = "test1";
RoundRobinLoadBalancer loadBalancer = new TestHintLoadBalancer(
ServiceInstanceListSuppliers.toProvider(serviceId,
instance(serviceId, "1host", false),
instance(serviceId, "2host-secure", true)),
serviceId);
Request<DefaultRequestContext> request = new DefaultRequest<>(
new DefaultRequestContext("test2"));
ServiceInstance serviceInstance = loadBalancer.choose(request).block()
.getServer();
assertThat(serviceInstance.getServiceId()).isEqualTo("test2");
}
private static class TestHintLoadBalancer extends RoundRobinLoadBalancer {
TestHintLoadBalancer(
ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,
String serviceId) {
super(serviceInstanceListSupplierProvider, serviceId);
}
@SuppressWarnings("rawtypes")
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
if (request.getContext() instanceof DefaultRequestContext) {
DefaultRequestContext requestContext = (DefaultRequestContext) request
.getContext();
return Mono.just(new DefaultResponse(
instance(requestContext.getHint(), "host", false)));
}
return Mono.empty();
}
}
@EnableAutoConfiguration

Loading…
Cancel
Save