Skip to content

Lb complete lifecycle #783

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jul 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/src/main/asciidoc/_configprops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
|spring.cloud.loadbalancer.health-check.initial-delay | | Initial delay value for the HealthCheck scheduler.
|spring.cloud.loadbalancer.health-check.interval | 25s | Interval for rerunning the HealthCheck scheduler.
|spring.cloud.loadbalancer.health-check.path | |
|spring.cloud.loadbalancer.hint | | Allows setting the value of <code>hint</code> that is passed on to the LoadBalancer request and can subsequently be used in {@link ReactiveLoadBalancer} implementations.
|spring.cloud.loadbalancer.retry.enabled | true |
|spring.cloud.loadbalancer.ribbon.enabled | true | Causes `RibbonLoadBalancerClient` to be used by default.
|spring.cloud.loadbalancer.service-discovery.timeout | | String representation of Duration of the timeout for calls to service discovery.
Expand Down
24 changes: 22 additions & 2 deletions docs/src/main/asciidoc/spring-cloud-commons.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -917,8 +917,7 @@ in order to avoid retrying calls on a failing instance.
`HealthCheckServiceInstanceListSupplier` uses properties prefixed with
`spring.cloud.loadbalancer.health-check`. You can set the `initialDelay` and `interval`
for the scheduler. You can set the default path for the healthcheck URL by setting
the value of the `spring.cloud.loadbalancer.health-check.path.default`. You can also set a specific value
for any given service by setting the value of the `spring.cloud.loadbalancer.health-check.path.[SERVICE_ID]`, substituting the `[SERVICE_ID]` with the correct ID of your service. If the path is not set, `/actuator/health` is used by default.
the value of the `spring.cloud.loadbalancer.health-check.path.default` property. You can also set a specific value for any given service by setting the value of the `spring.cloud.loadbalancer.health-check.path.[SERVICE_ID]` property, substituting `[SERVICE_ID]` with the correct ID of your service. If the path is not set, `/actuator/health` is used by default.

TIP:: If you rely on the default path (`/actuator/health`), make sure you add `spring-boot-starter-actuator` to your collaborator's dependencies, unless you are planning to add such an endpoint on your own.

Expand Down Expand Up @@ -947,6 +946,13 @@ public class CustomLoadBalancerConfiguration {

NOTE:: `HealthCheckServiceInstanceListSupplier` has its own caching mechanism based on Reactor Flux `replay()`, therefore, if it's being used, you may want to skip wrapping that supplier with `CachingServiceInstanceListSupplier`.

[[spring-cloud-loadbalancer-hints]]
=== Spring Cloud LoadBalancer Hints

Spring Cloud LoadBalancer lets you set `String` hints that are passed to the LoadBalancer within the `Request` object and that can later be used in `ReactiveLoadBalancer` implementations that can handle them.

You can set a default hint for all services by setting the value of the `spring.cloud.loadbalancer.hint.default` property. You can also set a specific value
for any given service by setting the value of the `spring.cloud.loadbalancer.hint.[SERVICE_ID]` property, substituting `[SERVICE_ID]` with the correct ID of your service. If the hint is not set by the user, `default` is used.

[[spring-cloud-loadbalancer-starter]]
=== Spring Cloud LoadBalancer Starter
Expand Down Expand Up @@ -1007,6 +1013,20 @@ public class MyConfiguration {
----
====

[[loadbalancer-lifecycle]]
=== Spring Cloud LoadBalancer Lifecycle

One type of bean that it may be useful to register using <<custom-loadbalancer-configuration,Custom LoadBalancer configuration>> is `LoadBalancerLifecycle`.

The LoadBalancerLifecycle beans provide callback methods, named `onStart(Request<RC> request)` and `onComplete(CompletionContext<RES, T> completionContext)`, that you should implement to specify what actions should take place before and after load-balancing.

`onStart(Request<RC> request)` takes a `Request` object as a parameter. It contains data that is used to select an appropriate instance, including the downstream client request and <<spring-cloud-loadbalancer-hints,hint>>. On the other hand, a `CompletionContext` object is provided to the `onComplete(CompletionContext<RES, T> completionContext)` method. It contains the LoadBalancer `Response`, including the selected service instance, the `Status` of the request executed against that service instance and (if available) the response returned to the downstream client, and (if an exception has occurred) the corresponding `Throwable`.

The `supports(Class requestContextClass, Class responseClass,
Class serverTypeClass)` method can be used to determine whether the processor in question handles objects of provided types. If not overridden by the user, it returns `true`.

NOTE: In the preceding method calls, `RC` means `RequestContext` type, `RES` means client response type, and `T` means returned server type.

== Spring Cloud Circuit Breaker

include::spring-cloud-circuitbreaker.adoc[leveloffset=+1]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2012-2020 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;

import org.springframework.web.reactive.function.client.ClientRequest;

/**
* @author Olga Maciaszek-Sharma
* @since 3.0.0
*/
public class ClientRequestContext extends DefaultRequestContext {

public ClientRequestContext(ClientRequest clientRequest) {
this(clientRequest, "default");
}

public ClientRequestContext(ClientRequest clientRequest, String hint) {
super(clientRequest, hint);
}

public ClientRequest getClientRequest() {
return (ClientRequest) super.getClientRequest();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,46 @@
import org.springframework.core.style.ToStringCreator;

/**
* Allows propagation of data related to load-balanced call completion status.
*
* @author Spencer Gibb
* @author Olga Maciaszek-Sharma
* @since 3.0.0
*/
// TODO: add metrics
public class CompletionContext {
public class CompletionContext<RES, T> {

private final Status status;

private final Throwable throwable;

private final Response<T> loadBalancerResponse;

private final RES clientResponse;

public CompletionContext(Status status) {
this(status, null);
this(status, null, null, null);
}

public CompletionContext(Status status, Response<T> response) {
this(status, null, response, null);
}

public CompletionContext(Status status, Throwable throwable,
Response<T> loadBalancerResponse) {
this(status, throwable, loadBalancerResponse, null);
}

public CompletionContext(Status status, Throwable throwable) {
public CompletionContext(Status status, Response<T> loadBalancerResponse,
RES clientResponse) {
this(status, null, loadBalancerResponse, clientResponse);
}

public CompletionContext(Status status, Throwable throwable,
Response<T> loadBalancerResponse, RES clientResponse) {
this.status = status;
this.throwable = throwable;
this.loadBalancerResponse = loadBalancerResponse;
this.clientResponse = clientResponse;
}

public Status status() {
Expand All @@ -45,11 +69,21 @@ public Throwable getThrowable() {
return this.throwable;
}

public Response<T> getLoadBalancerResponse() {
return loadBalancerResponse;
}

public RES getClientResponse() {
return clientResponse;
}

@Override
public String toString() {
ToStringCreator to = new ToStringCreator(this);
to.append("status", this.status);
to.append("throwable", this.throwable);
to.append("loadBalancerResponse", loadBalancerResponse);
to.append("clientResponse", clientResponse);
return to.toString();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package org.springframework.cloud.client.loadbalancer;

import org.springframework.core.style.ToStringCreator;

/**
* A default implementation of {@link Request}.
*
Expand Down Expand Up @@ -43,4 +45,11 @@ public void setContext(T context) {
this.context = context;
}

@Override
public String toString() {
ToStringCreator to = new ToStringCreator(this);
to.append("context", context);
return to.toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,43 @@

package org.springframework.cloud.client.loadbalancer;

import org.springframework.core.style.ToStringCreator;

/**
* Contains information relevant to the request.
*
* @author Olga Maciaszek-Sharma
*/
public class DefaultRequestContext {
public class DefaultRequestContext extends HintRequestContext {

/**
* A {@link String} value of hint that can be used to choose the correct service
* instance.
* The request to be executed against the service instance selected by the
* LoadBalancer.
*/
private String hint = "default";
private final Object clientRequest;

public DefaultRequestContext() {
clientRequest = null;
}

public DefaultRequestContext(Object clientRequest) {
this.clientRequest = clientRequest;
}

public DefaultRequestContext(String hint) {
this.hint = hint;
public DefaultRequestContext(Object clientRequest, String hint) {
super(hint);
this.clientRequest = clientRequest;
}

public String getHint() {
return hint;
public Object getClientRequest() {
return clientRequest;
}

public void setHint(String hint) {
this.hint = hint;
@Override
public String toString() {
ToStringCreator to = new ToStringCreator(this);
to.append("clientRequest", clientRequest);
return to.toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
package org.springframework.cloud.client.loadbalancer;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.core.style.ToStringCreator;

/**
* @author Spencer Gibb
* @author Olga Maciaszek-Sharma
*/
public class DefaultResponse implements Response<ServiceInstance> {

Expand All @@ -41,7 +43,14 @@ public ServiceInstance getServer() {

@Override
public void onComplete(CompletionContext completionContext) {
// TODO: implement
// do nothing: deprecated interface method
}

@Override
public String toString() {
ToStringCreator to = new ToStringCreator(this);
to.append("serviceInstance", serviceInstance);
return to.toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public ServiceInstance getServer() {

@Override
public void onComplete(CompletionContext completionContext) {
// TODO: implement
// do nothing: deprecated interface method
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2012-2020 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;

import org.springframework.core.style.ToStringCreator;

/**
* Allows propagating hints to the LoadBalancer.
*
* @author Olga Maciaszek-Sharma
*/
public class HintRequestContext {

/**
* A {@link String} value of hint that can be used to choose the correct service
* instance.
*/
private String hint = "default";

public HintRequestContext() {
}

public HintRequestContext(String hint) {
this.hint = hint;
}

public String getHint() {
return hint;
}

public void setHint(String hint) {
this.hint = hint;
}

@Override
public String toString() {
ToStringCreator to = new ToStringCreator(this);
to.append("hint", hint);
return to.toString();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2012-2020 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;

import org.springframework.http.HttpRequest;

/**
* @author Olga Maciaszek-Sharma
*/
public class HttpRequestContext extends DefaultRequestContext {

public HttpRequestContext(HttpRequest httpRequest) {
this(httpRequest, "default");
}

public HttpRequestContext(HttpRequest httpRequest, String hint) {
super(httpRequest, hint);
}

public HttpRequest getClientRequest() {
return (HttpRequest) super.getClientRequest();
}

}
Loading