diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java index ebe3e64d0..d1efe9660 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java @@ -181,6 +181,14 @@ public class EurekaClientAutoConfiguration { if (metadataMap.get("management.port") == null) { metadataMap.put("management.port", String.valueOf(metadata.getManagementPort())); } + } else { + //without the metadata the status and health check URLs will not be set + //and the status page and health check url paths will not include the + //context path so set them here + if(StringUtils.hasText(managementContextPath)) { + instance.setHealthCheckUrlPath(managementContextPath + instance.getHealthCheckUrlPath()); + instance.setStatusPageUrlPath(managementContextPath + instance.getStatusPageUrlPath()); + } } setupJmxPort(instance, jmxPort); diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaHealthIndicator.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaHealthIndicator.java index d7dc499a6..e705375bd 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaHealthIndicator.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaHealthIndicator.java @@ -20,10 +20,12 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import org.springframework.aop.support.AopUtils; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Health.Builder; import org.springframework.boot.actuate.health.Status; import org.springframework.cloud.client.discovery.health.DiscoveryHealthIndicator; +import org.springframework.cloud.util.ProxyUtils; import com.netflix.appinfo.EurekaInstanceConfig; import com.netflix.discovery.DiscoveryClient; @@ -68,9 +70,8 @@ public class EurekaHealthIndicator implements DiscoveryHealthIndicator { Status status = new Status( this.eurekaClient.getInstanceRemoteStatus().toString(), "Remote status from Eureka server"); - - if (eurekaClient instanceof DiscoveryClient && clientConfig.shouldFetchRegistry()) { - DiscoveryClient discoveryClient = (DiscoveryClient) eurekaClient; + DiscoveryClient discoveryClient = getDiscoveryClient(); + if (discoveryClient != null && clientConfig.shouldFetchRegistry()) { long lastFetch = discoveryClient.getLastSuccessfulRegistryFetchTimePeriod(); if (lastFetch < 0) { @@ -90,6 +91,16 @@ public class EurekaHealthIndicator implements DiscoveryHealthIndicator { return status; } + private DiscoveryClient getDiscoveryClient() { + DiscoveryClient discoveryClient = null; + if(AopUtils.isAopProxy(eurekaClient)) { + discoveryClient = ProxyUtils.getTargetObject(eurekaClient); + } else if(DiscoveryClient.class.isInstance(eurekaClient)) { + discoveryClient = (DiscoveryClient)eurekaClient; + } + return discoveryClient; + } + private Map getApplications() { Applications applications = this.eurekaClient.getApplications(); if (applications == null) { @@ -97,7 +108,9 @@ public class EurekaHealthIndicator implements DiscoveryHealthIndicator { } Map result = new HashMap<>(); for (Application application : applications.getRegisteredApplications()) { - result.put(application.getName(), application.getInstances().size()); + if (!application.getInstances().isEmpty()) { + result.put(application.getName(), application.getInstances().size()); + } } return result; } diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfigurationTests.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfigurationTests.java index d3536628c..eb3a57db9 100644 --- a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfigurationTests.java +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfigurationTests.java @@ -228,6 +228,20 @@ public class EurekaClientAutoConfigurationTests { instance.getHealthCheckUrl().endsWith(":8989/management/actuator/health")); } + @Test + public void statusPageUrl_and_healthCheckUrl_contain_management_context_path_random_port() throws Exception { + addEnvironment(this.context, + "server.port=0", "management.server.servlet.context-path=/management"); + + setupContext(RefreshAutoConfiguration.class); + EurekaInstanceConfigBean instance = this.context + .getBean(EurekaInstanceConfigBean.class); + assertTrue("Wrong status page: " + instance.getStatusPageUrlPath(), + instance.getStatusPageUrlPath().equals("/management/actuator/info")); + assertTrue("Wrong health check: " + instance.getHealthCheckUrlPath(), + instance.getHealthCheckUrlPath().equals("/management/actuator/health")); + } + @Test public void statusPageUrlPathAndManagementPortAndContextPath() { TestPropertyValues.of( "server.port=8989", diff --git a/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/apache/HttpClientRibbonConfiguration.java b/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/apache/HttpClientRibbonConfiguration.java index afad077f0..a02b4b1ae 100644 --- a/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/apache/HttpClientRibbonConfiguration.java +++ b/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/apache/HttpClientRibbonConfiguration.java @@ -36,6 +36,7 @@ import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory; import org.springframework.cloud.commons.httpclient.ApacheHttpClientConnectionManagerFactory; import org.springframework.cloud.commons.httpclient.ApacheHttpClientFactory; import org.springframework.cloud.netflix.ribbon.RibbonClientName; +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerContext; import org.springframework.cloud.netflix.ribbon.RibbonProperties; import org.springframework.cloud.netflix.ribbon.ServerIntrospector; import org.springframework.context.annotation.Bean; @@ -133,11 +134,13 @@ public class HttpClientRibbonConfiguration { public RetryableRibbonLoadBalancingHttpClient retryableRibbonLoadBalancingHttpClient( IClientConfig config, ServerIntrospector serverIntrospector, ILoadBalancer loadBalancer, RetryHandler retryHandler, - LoadBalancedRetryFactory loadBalancedRetryFactory, CloseableHttpClient httpClient) { + LoadBalancedRetryFactory loadBalancedRetryFactory, CloseableHttpClient httpClient, + RibbonLoadBalancerContext ribbonLoadBalancerContext) { RetryableRibbonLoadBalancingHttpClient client = new RetryableRibbonLoadBalancingHttpClient( httpClient, config, serverIntrospector, loadBalancedRetryFactory); client.setLoadBalancer(loadBalancer); client.setRetryHandler(retryHandler); + client.setRibbonLoadBalancerContext(ribbonLoadBalancerContext); Monitors.registerObject("Client_" + this.name, client); return client; } diff --git a/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/apache/RetryableRibbonLoadBalancingHttpClient.java b/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/apache/RetryableRibbonLoadBalancingHttpClient.java index bd3606913..fc390653d 100644 --- a/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/apache/RetryableRibbonLoadBalancingHttpClient.java +++ b/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/apache/RetryableRibbonLoadBalancingHttpClient.java @@ -16,6 +16,9 @@ package org.springframework.cloud.netflix.ribbon.apache; import java.net.URI; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.http.HttpResponse; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpUriRequest; @@ -28,7 +31,10 @@ import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy; import org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser; import org.springframework.cloud.client.loadbalancer.InterceptorRetryPolicy; import org.springframework.cloud.netflix.ribbon.RibbonProperties; +import org.springframework.cloud.netflix.ribbon.RibbonStatsRecorder; import org.springframework.cloud.netflix.ribbon.ServerIntrospector; +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.RibbonServer; +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerContext; import org.springframework.cloud.netflix.ribbon.support.ContextAwareRequest; import org.springframework.http.HttpRequest; import org.springframework.retry.RecoveryCallback; @@ -50,7 +56,10 @@ import com.netflix.client.config.IClientConfig; * @author Gang Li */ public class RetryableRibbonLoadBalancingHttpClient extends RibbonLoadBalancingHttpClient { + private static final Log LOGGER = LogFactory.getLog(RetryableRibbonLoadBalancingHttpClient.class); + private LoadBalancedRetryFactory loadBalancedRetryFactory; + private RibbonLoadBalancerContext ribbonLoadBalancerContext; public RetryableRibbonLoadBalancingHttpClient(CloseableHttpClient delegate, IClientConfig config, ServerIntrospector serverIntrospector, @@ -75,6 +84,7 @@ public class RetryableRibbonLoadBalancingHttpClient extends RibbonLoadBalancingH //on retries the policy will choose the server and set it in the context //extract the server and update the request being made RibbonApacheHttpRequest newRequest = request; + RibbonStatsRecorder statsRecorder = null; if (context instanceof LoadBalancedRetryContext) { ServiceInstance service = ((LoadBalancedRetryContext) context).getServiceInstance(); validateServiceInstance(service); @@ -85,6 +95,12 @@ public class RetryableRibbonLoadBalancingHttpClient extends RibbonLoadBalancingH .port(service.getPort()).path(newRequest.getURI().getPath()) .query(newRequest.getURI().getQuery()).fragment(newRequest.getURI().getFragment()) .build().encode().toUri()); + + if (ribbonLoadBalancerContext == null) { + LOGGER.error("RibbonLoadBalancerContext is null. Unable to update load balancer stats"); + } else if (service instanceof RibbonServer) { + statsRecorder = new RibbonStatsRecorder(ribbonLoadBalancerContext, ((RibbonServer)service).getServer()); + } } } newRequest = getSecureRequest(newRequest, configOverride); @@ -94,6 +110,9 @@ public class RetryableRibbonLoadBalancingHttpClient extends RibbonLoadBalancingH throw new HttpClientStatusCodeException(RetryableRibbonLoadBalancingHttpClient.this.clientName, httpResponse, HttpClientUtils.createEntity(httpResponse), httpUriRequest.getURI()); } + if (statsRecorder != null) { + statsRecorder.recordStats(httpResponse); + } return new RibbonApacheHttpResponse(httpResponse, httpUriRequest.getURI()); }; LoadBalancedRecoveryCallback recoveryCallback = new LoadBalancedRecoveryCallback() { @@ -101,7 +120,7 @@ public class RetryableRibbonLoadBalancingHttpClient extends RibbonLoadBalancingH protected RibbonApacheHttpResponse createResponse(HttpResponse response, URI uri) { return new RibbonApacheHttpResponse(response, uri); } - }; + }; return this.executeWithRetry(request, retryPolicy, retryCallback, recoveryCallback); } @@ -144,4 +163,9 @@ public class RetryableRibbonLoadBalancingHttpClient extends RibbonLoadBalancingH super(request, policy, serviceInstanceChooser, serviceName); } } + + public void setRibbonLoadBalancerContext(RibbonLoadBalancerContext ribbonLoadBalancerContext) { + this.ribbonLoadBalancerContext = ribbonLoadBalancerContext; + } + } diff --git a/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/okhttp/OkHttpRibbonConfiguration.java b/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/okhttp/OkHttpRibbonConfiguration.java index 486ac529c..51b6edb2a 100644 --- a/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/okhttp/OkHttpRibbonConfiguration.java +++ b/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/okhttp/OkHttpRibbonConfiguration.java @@ -30,6 +30,7 @@ import org.springframework.cloud.commons.httpclient.OkHttpClientConnectionPoolFa import org.springframework.cloud.commons.httpclient.OkHttpClientFactory; import org.springframework.cloud.netflix.ribbon.RibbonClientName; import org.springframework.cloud.netflix.ribbon.RibbonProperties; +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerContext; import org.springframework.cloud.netflix.ribbon.ServerIntrospector; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -100,11 +101,12 @@ public class OkHttpRibbonConfiguration { ILoadBalancer loadBalancer, RetryHandler retryHandler, LoadBalancedRetryFactory loadBalancedRetryFactory, - OkHttpClient delegate) { + OkHttpClient delegate, RibbonLoadBalancerContext ribbonLoadBalancerContext) { RetryableOkHttpLoadBalancingClient client = new RetryableOkHttpLoadBalancingClient(delegate, config, serverIntrospector, loadBalancedRetryFactory); client.setLoadBalancer(loadBalancer); client.setRetryHandler(retryHandler); + client.setRibbonLoadBalancerContext(ribbonLoadBalancerContext); Monitors.registerObject("Client_" + this.name, client); return client; } diff --git a/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/okhttp/RetryableOkHttpLoadBalancingClient.java b/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/okhttp/RetryableOkHttpLoadBalancingClient.java index d62af2b7f..825024320 100644 --- a/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/okhttp/RetryableOkHttpLoadBalancingClient.java +++ b/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/okhttp/RetryableOkHttpLoadBalancingClient.java @@ -21,6 +21,8 @@ import okhttp3.Response; import okhttp3.ResponseBody; import java.net.URI; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.InterceptorRetryPolicy; import org.springframework.cloud.client.loadbalancer.LoadBalancedRecoveryCallback; @@ -28,6 +30,10 @@ import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryContext; import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory; import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy; import org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser; +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerContext; +import org.springframework.cloud.netflix.ribbon.RibbonStatsRecorder; +import org.springframework.cloud.netflix.ribbon.ServerIntrospector; +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.RibbonServer; import org.springframework.cloud.netflix.ribbon.support.ContextAwareRequest; import org.springframework.http.HttpRequest; import org.springframework.retry.RecoveryCallback; @@ -39,7 +45,6 @@ import org.springframework.retry.backoff.NoBackOffPolicy; import org.springframework.retry.policy.NeverRetryPolicy; import org.springframework.retry.support.RetryTemplate; import org.springframework.web.util.UriComponentsBuilder; -import org.springframework.cloud.netflix.ribbon.ServerIntrospector; import com.netflix.client.RequestSpecificRetryHandler; import com.netflix.client.RetryHandler; @@ -51,8 +56,10 @@ import com.netflix.client.config.IClientConfig; * @author Gang Li */ public class RetryableOkHttpLoadBalancingClient extends OkHttpLoadBalancingClient { + private static final Log LOGGER = LogFactory.getLog(RetryableOkHttpLoadBalancingClient.class); private LoadBalancedRetryFactory loadBalancedRetryFactory; + private RibbonLoadBalancerContext ribbonLoadBalancerContext; public RetryableOkHttpLoadBalancingClient(OkHttpClient delegate, IClientConfig config, ServerIntrospector serverIntrospector, LoadBalancedRetryFactory loadBalancedRetryPolicyFactory) { @@ -98,6 +105,8 @@ public class RetryableOkHttpLoadBalancingClient extends OkHttpLoadBalancingClien //on retries the policy will choose the server and set it in the context //extract the server and update the request being made OkHttpRibbonRequest newRequest = ribbonRequest; + RibbonStatsRecorder statsRecorder = null; + if(context instanceof LoadBalancedRetryContext) { ServiceInstance service = ((LoadBalancedRetryContext)context).getServiceInstance(); validateServiceInstance(service); @@ -106,6 +115,12 @@ public class RetryableOkHttpLoadBalancingClient extends OkHttpLoadBalancingClien newRequest.getURI().getUserInfo(), service.getHost(), service.getPort(), newRequest.getURI().getPath(), newRequest.getURI().getQuery(), newRequest.getURI().getFragment())); + + if (ribbonLoadBalancerContext == null) { + LOGGER.error("RibbonLoadBalancerContext is null. Unable to update load balancer stats"); + } else if (service instanceof RibbonServer) { + statsRecorder = new RibbonStatsRecorder(ribbonLoadBalancerContext, ((RibbonServer)service).getServer()); + } } if (isSecure(configOverride)) { final URI secureUri = UriComponentsBuilder.fromUri(newRequest.getUri()) @@ -122,6 +137,9 @@ public class RetryableOkHttpLoadBalancingClient extends OkHttpLoadBalancingClien throw new OkHttpStatusCodeException(RetryableOkHttpLoadBalancingClient.this.clientName, response, responseBody, newRequest.getURI()); } + if (statsRecorder != null) { + statsRecorder.recordStats(response); + } return new OkHttpRibbonResponse(response, newRequest.getUri()); } }; @@ -134,12 +152,14 @@ public class RetryableOkHttpLoadBalancingClient extends OkHttpLoadBalancingClien }); } - - @Override public RequestSpecificRetryHandler getRequestSpecificRetryHandler(OkHttpRibbonRequest request, IClientConfig requestConfig) { return new RequestSpecificRetryHandler(false, false, RetryHandler.DEFAULT, null); } + + public void setRibbonLoadBalancerContext(RibbonLoadBalancerContext ribbonLoadBalancerContext) { + this.ribbonLoadBalancerContext = ribbonLoadBalancerContext; + } static class RetryPolicy extends InterceptorRetryPolicy { public RetryPolicy(HttpRequest request, LoadBalancedRetryPolicy policy, ServiceInstanceChooser serviceInstanceChooser, String serviceName) { diff --git a/spring-cloud-netflix-ribbon/src/test/java/org/springframework/cloud/netflix/ribbon/apache/RibbonLoadBalancingHttpClientTests.java b/spring-cloud-netflix-ribbon/src/test/java/org/springframework/cloud/netflix/ribbon/apache/RibbonLoadBalancingHttpClientTests.java index 2c72498fb..57eaf2584 100644 --- a/spring-cloud-netflix-ribbon/src/test/java/org/springframework/cloud/netflix/ribbon/apache/RibbonLoadBalancingHttpClientTests.java +++ b/spring-cloud-netflix-ribbon/src/test/java/org/springframework/cloud/netflix/ribbon/apache/RibbonLoadBalancingHttpClientTests.java @@ -23,6 +23,8 @@ import java.io.InputStream; import java.net.URI; import java.util.ArrayList; import java.util.Locale; +import java.util.concurrent.TimeUnit; + import org.apache.http.HttpEntity; import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; @@ -71,7 +73,10 @@ import com.netflix.client.config.DefaultClientConfigImpl; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancer; import com.netflix.loadbalancer.ILoadBalancer; +import com.netflix.loadbalancer.LoadBalancerStats; import com.netflix.loadbalancer.Server; +import com.netflix.loadbalancer.ServerStats; +import com.netflix.servo.monitor.Monitors; import static org.hamcrest.Matchers.is; import static org.hamcrest.CoreMatchers.containsString; @@ -116,6 +121,7 @@ public class RibbonLoadBalancingHttpClientTests { RequestConfig result = getBuiltRequestConfig(UseDefaults.class, null); assertThat(result.isRedirectsEnabled(), is(false)); + } @Test @@ -249,9 +255,11 @@ public class RibbonLoadBalancingHttpClientTests { doReturn(locale).when(fourOFourResponse).getLocale(); doReturn(fourOFourResponse).when(delegate).execute(any(HttpUriRequest.class)); ILoadBalancer lb = mock(ILoadBalancer.class); + RibbonLoadBalancerContext ribbonLoadBalancerContext = new RibbonLoadBalancerContext(lb); MyBackOffPolicy myBackOffPolicy = new MyBackOffPolicy(); RetryableRibbonLoadBalancingHttpClient client = setupClientForRetry(retriesNextServer, retriesSameServer, retryable, retryOnAllOps, serviceName, host, port, delegate, lb, "404", myBackOffPolicy); + client.setRibbonLoadBalancerContext(ribbonLoadBalancerContext); RibbonApacheHttpRequest request = mock(RibbonApacheHttpRequest.class); doReturn(uri).when(request).getURI(); doReturn(method).when(request).getMethod(); @@ -364,9 +372,17 @@ public class RibbonLoadBalancingHttpClientTests { doReturn(200).when(statusLine).getStatusCode(); doReturn(statusLine).when(response).getStatusLine(); doThrow(new IOException("boom")).doReturn(response).when(delegate).execute(any(HttpUriRequest.class)); - ILoadBalancer lb = mock(ILoadBalancer.class); + AbstractLoadBalancer lb = mock(AbstractLoadBalancer.class); + LoadBalancerStats lbStats = mock(LoadBalancerStats.class); + doReturn(lbStats).when(lb).getLoadBalancerStats(); + ServerStats serverStats = mock(ServerStats.class); + doReturn(serverStats).when(lbStats).getSingleServerStat(any(Server.class)); + RibbonLoadBalancerContext ribbonLoadBalancerContext = mock(RibbonLoadBalancerContext.class); + doReturn(lb).when(ribbonLoadBalancerContext).getLoadBalancer(); + doReturn(Monitors.newTimer("_LoadBalancerExecutionTimer", TimeUnit.MILLISECONDS)).when(ribbonLoadBalancerContext).getExecuteTracer(); RetryableRibbonLoadBalancingHttpClient client = setupClientForRetry(retriesNextServer, retriesSameServer, retryable, retryOnAllOps, serviceName, host, port, delegate, lb, "", null); + client.setRibbonLoadBalancerContext(ribbonLoadBalancerContext); RibbonApacheHttpRequest request = mock(RibbonApacheHttpRequest.class); doReturn(uri).when(request).getURI(); doReturn(method).when(request).getMethod(); @@ -377,6 +393,7 @@ public class RibbonLoadBalancingHttpClientTests { RibbonApacheHttpResponse returnedResponse = client.execute(request, null); verify(delegate, times(2)).execute(any(HttpUriRequest.class)); verify(lb, times(1)).chooseServer(eq(serviceName)); + verify(ribbonLoadBalancerContext, times(1)).noteRequestCompletion(serverStats, response, null, 0, null); } @Test @@ -398,9 +415,11 @@ public class RibbonLoadBalancingHttpClientTests { doThrow(new IOException("boom")).doThrow(new IOException("boom again")).doReturn(response). when(delegate).execute(any(HttpUriRequest.class)); ILoadBalancer lb = mock(ILoadBalancer.class); + RibbonLoadBalancerContext ribbonLoadBalancerContext = new RibbonLoadBalancerContext(lb); MyBackOffPolicy myBackOffPolicy = new MyBackOffPolicy(); RetryableRibbonLoadBalancingHttpClient client = setupClientForRetry(retriesNextServer, retriesSameServer, retryable, retryOnAllOps, serviceName, host, port, delegate, lb, "", myBackOffPolicy); + client.setRibbonLoadBalancerContext(ribbonLoadBalancerContext); RibbonApacheHttpRequest request = mock(RibbonApacheHttpRequest.class); doReturn(uri).when(request).getURI(); doReturn(method).when(request).getMethod(); @@ -433,9 +452,11 @@ public class RibbonLoadBalancingHttpClientTests { doThrow(new IOException("boom")).doThrow(new IOException("boom again")).doReturn(response). when(delegate).execute(any(HttpUriRequest.class)); ILoadBalancer lb = mock(ILoadBalancer.class); + RibbonLoadBalancerContext ribbonLoadBalancerContext = new RibbonLoadBalancerContext(lb); MyBackOffPolicy myBackOffPolicy = new MyBackOffPolicy(); RetryableRibbonLoadBalancingHttpClient client = setupClientForRetry(retriesNextServer, retriesSameServer, retryable, retryOnAllOps, serviceName, host, port, delegate, lb, "", myBackOffPolicy); + client.setRibbonLoadBalancerContext(ribbonLoadBalancerContext); RibbonApacheHttpRequest request = mock(RibbonApacheHttpRequest.class); doReturn(method).when(request).getMethod(); doReturn(uri).when(request).getURI(); @@ -510,8 +531,10 @@ public class RibbonLoadBalancingHttpClientTests { doReturn(response). when(delegate).execute(any(HttpUriRequest.class)); ILoadBalancer lb = mock(ILoadBalancer.class); + RibbonLoadBalancerContext ribbonLoadBalancerContext = new RibbonLoadBalancerContext(lb); RetryableRibbonLoadBalancingHttpClient client = setupClientForRetry(retriesNextServer, retriesSameServer, retryable, retryOnAllOps, serviceName, host, port, delegate, lb, "", null,true); + client.setRibbonLoadBalancerContext(ribbonLoadBalancerContext); client.execute(request, null); verify(response, times(0)).close(); verify(delegate, times(1)).execute(argThat(new ArgumentMatcher() { @@ -542,8 +565,10 @@ public class RibbonLoadBalancingHttpClientTests { doThrow(new IOException("boom")).doThrow(new IOException("boom again")).doReturn(response). when(delegate).execute(any(HttpUriRequest.class)); ILoadBalancer lb = mock(ILoadBalancer.class); + RibbonLoadBalancerContext ribbonLoadBalancerContext = new RibbonLoadBalancerContext(lb); RetryableRibbonLoadBalancingHttpClient client = setupClientForRetry(retriesNextServer, retriesSameServer, retryable, retryOnAllOps, serviceName, host, port, delegate, lb, "", null); + client.setRibbonLoadBalancerContext(ribbonLoadBalancerContext); RibbonApacheHttpRequest request = mock(RibbonApacheHttpRequest.class); doReturn(method).when(request).getMethod(); doReturn(uri).when(request).getURI(); @@ -590,9 +615,11 @@ public class RibbonLoadBalancingHttpClientTests { doReturn(fourOFourStatusLine).when(fourOFourResponse).getStatusLine(); doReturn(fourOFourResponse).doReturn(response).when(delegate).execute(any(HttpUriRequest.class)); ILoadBalancer lb = mock(ILoadBalancer.class); + RibbonLoadBalancerContext ribbonLoadBalancerContext = new RibbonLoadBalancerContext(lb); MyBackOffPolicy myBackOffPolicy = new MyBackOffPolicy(); RetryableRibbonLoadBalancingHttpClient client = setupClientForRetry(retriesNextServer, retriesSameServer, retryable, retryOnAllOps, serviceName, host, port, delegate, lb, "404", myBackOffPolicy); + client.setRibbonLoadBalancerContext(ribbonLoadBalancerContext); RibbonApacheHttpRequest request = mock(RibbonApacheHttpRequest.class); doReturn(uri).when(request).getURI(); doReturn(method).when(request).getMethod(); @@ -626,10 +653,12 @@ public class RibbonLoadBalancingHttpClientTests { doThrow(new IOException("boom")).doThrow(new IOException("boom again")).doReturn(response). when(delegate).execute(any(HttpUriRequest.class)); ILoadBalancer lb = mock(ILoadBalancer.class); + RibbonLoadBalancerContext ribbonLoadBalancerContext = new RibbonLoadBalancerContext(lb); MyBackOffPolicy myBackOffPolicy = new MyBackOffPolicy(); MyRetryListener myRetryListener = new MyRetryListener(); RetryableRibbonLoadBalancingHttpClient client = setupClientForRetry(retriesNextServer, retriesSameServer, retryable, retryOnAllOps, serviceName, host, port, delegate, lb, "", myBackOffPolicy, false, new RetryListener[]{myRetryListener}); + client.setRibbonLoadBalancerContext(ribbonLoadBalancerContext); RibbonApacheHttpRequest request = mock(RibbonApacheHttpRequest.class); doReturn(method).when(request).getMethod(); doReturn(uri).when(request).getURI(); @@ -663,10 +692,12 @@ public class RibbonLoadBalancingHttpClientTests { doThrow(new IOException("boom")).doThrow(new IOException("boom again")).doReturn(response). when(delegate).execute(any(HttpUriRequest.class)); ILoadBalancer lb = mock(ILoadBalancer.class); + RibbonLoadBalancerContext ribbonLoadBalancerContext = new RibbonLoadBalancerContext(lb); MyBackOffPolicy myBackOffPolicy = new MyBackOffPolicy(); MyRetryListener myRetryListener = new MyRetryListener(); RetryableRibbonLoadBalancingHttpClient client = setupClientForRetry(retriesNextServer, retriesSameServer, retryable, retryOnAllOps, serviceName, host, port, delegate, lb, "", myBackOffPolicy, false, new RetryListener[]{}); + client.setRibbonLoadBalancerContext(ribbonLoadBalancerContext); RibbonApacheHttpRequest request = mock(RibbonApacheHttpRequest.class); doReturn(method).when(request).getMethod(); doReturn(uri).when(request).getURI(); @@ -733,9 +764,11 @@ public class RibbonLoadBalancingHttpClientTests { doThrow(new IOException("boom")).doThrow(new IOException("boom again")).doReturn(response). when(delegate).execute(any(HttpUriRequest.class)); ILoadBalancer lb = mock(ILoadBalancer.class); + RibbonLoadBalancerContext ribbonLoadBalancerContext = new RibbonLoadBalancerContext(lb); MyBackOffPolicy myBackOffPolicy = new MyBackOffPolicy(); RetryableRibbonLoadBalancingHttpClient client = setupClientForRetry(retriesNextServer, retriesSameServer, retryable, retryOnAllOps, serviceName, host, port, delegate, lb, "", myBackOffPolicy, false); + client.setRibbonLoadBalancerContext(ribbonLoadBalancerContext); RibbonApacheHttpRequest request = mock(RibbonApacheHttpRequest.class); doReturn(method).when(request).getMethod(); doReturn(uri).when(request).getURI(); @@ -768,6 +801,7 @@ public class RibbonLoadBalancingHttpClientTests { RetryableRibbonLoadBalancingHttpClient client = new RetryableRibbonLoadBalancingHttpClient(delegate, clientConfig, introspector, factory); client.setLoadBalancer(lb); + client.setRibbonLoadBalancerContext(context); ReflectionTestUtils.setField(client, "delegate", delegate); return client; } diff --git a/spring-cloud-netflix-ribbon/src/test/java/org/springframework/cloud/netflix/ribbon/okhttp/SpringRetryEnabledOkHttpClientTests.java b/spring-cloud-netflix-ribbon/src/test/java/org/springframework/cloud/netflix/ribbon/okhttp/SpringRetryEnabledOkHttpClientTests.java index 276a340bd..b08e532fb 100644 --- a/spring-cloud-netflix-ribbon/src/test/java/org/springframework/cloud/netflix/ribbon/okhttp/SpringRetryEnabledOkHttpClientTests.java +++ b/spring-cloud-netflix-ribbon/src/test/java/org/springframework/cloud/netflix/ribbon/okhttp/SpringRetryEnabledOkHttpClientTests.java @@ -20,6 +20,8 @@ import okhttp3.Request; import java.net.URI; import java.util.Map; + +import org.hamcrest.core.IsNull; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.BeansException; @@ -40,6 +42,7 @@ import org.springframework.http.HttpMethod; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.util.ReflectionTestUtils; + import com.netflix.client.ClientException; import com.netflix.client.DefaultLoadBalancerRetryHandler; import com.netflix.client.RetryHandler; @@ -83,6 +86,12 @@ public class SpringRetryEnabledOkHttpClientTests implements ApplicationContextAw assertThat(clients.values(), hasSize(1)); assertThat(clients.values().toArray()[0], instanceOf(RetryableOkHttpLoadBalancingClient.class)); + + RibbonLoadBalancerContext ribbonLoadBalancerContext = (RibbonLoadBalancerContext) ReflectionTestUtils + .getField(clients.values().toArray()[0], RetryableOkHttpLoadBalancingClient.class, "ribbonLoadBalancerContext"); + assertThat("RetryableOkHttpLoadBalancingClient.ribbonLoadBalancerContext should not be null", + ribbonLoadBalancerContext, IsNull.notNullValue()); + } @Override