Commit 0b8f8552 by Dave Syer

Refresh health indicator for config server if present

Listen for heartbeats from discovery so that state changes can trigger a new status (and the client doesn't rely on the old address of the server if it has now changed). Fixes gh-232
parent dafb5ecf
...@@ -22,15 +22,16 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -22,15 +22,16 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
import org.springframework.cloud.client.discovery.event.HeartbeatMonitor;
import org.springframework.cloud.config.client.ConfigClientProperties; import org.springframework.cloud.config.client.ConfigClientProperties;
import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator; import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator;
import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration; import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.context.event.SmartApplicationListener;
import org.springframework.core.env.Environment;
import com.netflix.appinfo.InstanceInfo; import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.DiscoveryClient; import com.netflix.discovery.DiscoveryClient;
...@@ -48,7 +49,9 @@ import com.netflix.discovery.DiscoveryClient; ...@@ -48,7 +49,9 @@ import com.netflix.discovery.DiscoveryClient;
@Import(EurekaClientAutoConfiguration.class) @Import(EurekaClientAutoConfiguration.class)
@CommonsLog @CommonsLog
public class DiscoveryClientConfigServiceBootstrapConfiguration implements public class DiscoveryClientConfigServiceBootstrapConfiguration implements
ApplicationListener<ContextRefreshedEvent> { SmartApplicationListener {
private HeartbeatMonitor monitor = new HeartbeatMonitor();
@Autowired @Autowired
private DiscoveryClient client; private DiscoveryClient client;
...@@ -57,14 +60,36 @@ public class DiscoveryClientConfigServiceBootstrapConfiguration implements ...@@ -57,14 +60,36 @@ public class DiscoveryClientConfigServiceBootstrapConfiguration implements
private ConfigClientProperties config; private ConfigClientProperties config;
@Override @Override
public void onApplicationEvent(ContextRefreshedEvent event) { public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
refresh();
}
else if (event instanceof HeartbeatEvent) {
if (this.monitor.update(((HeartbeatEvent) event).getValue())) {
refresh();
}
}
}
@Override
public int getOrder() {
return 0;
}
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ContextRefreshedEvent.class.isAssignableFrom(eventType)
|| HeartbeatEvent.class.isAssignableFrom(eventType);
}
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return true;
}
private void refresh() {
try { try {
log.info("Locating configserver via discovery"); log.info("Locating configserver via discovery");
Environment environment = event.getApplicationContext().getEnvironment();
if (!(environment instanceof ConfigurableEnvironment)) {
log.info("Environment is not ConfigurableEnvironment so cannot look up configserver");
return;
}
InstanceInfo server = this.client.getNextServerFromEureka(this.config InstanceInfo server = this.client.getNextServerFromEureka(this.config
.getDiscovery().getServiceId(), false); .getDiscovery().getServiceId(), false);
String url = server.getHomePageUrl(); String url = server.getHomePageUrl();
......
...@@ -24,7 +24,17 @@ import org.springframework.context.annotation.Configuration; ...@@ -24,7 +24,17 @@ import org.springframework.context.annotation.Configuration;
import com.netflix.client.config.DefaultClientConfigImpl; import com.netflix.client.config.DefaultClientConfigImpl;
import com.netflix.client.config.IClientConfig; import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.*; import com.netflix.loadbalancer.ConfigurationBasedServerList;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.LoadBalancerBuilder;
import com.netflix.loadbalancer.NoOpPing;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import com.netflix.loadbalancer.ServerListFilter;
import com.netflix.loadbalancer.ZoneAvoidanceRule;
import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
import com.netflix.niws.client.http.RestClient; import com.netflix.niws.client.http.RestClient;
import com.netflix.servo.monitor.Monitors; import com.netflix.servo.monitor.Monitors;
...@@ -85,15 +95,11 @@ public class RibbonClientConfiguration { ...@@ -85,15 +95,11 @@ public class RibbonClientConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config, public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
ServerList<Server> serverList, ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
ServerListFilter<Server> serverListFilter,
IRule rule, IPing ping) { IRule rule, IPing ping) {
ZoneAwareLoadBalancer<Server> balancer = LoadBalancerBuilder.newBuilder() ZoneAwareLoadBalancer<Server> balancer = LoadBalancerBuilder.newBuilder()
.withClientConfig(config) .withClientConfig(config).withRule(rule).withPing(ping)
.withRule(rule) .withServerListFilter(serverListFilter).withDynamicServerList(serverList)
.withPing(ping)
.withServerListFilter(serverListFilter)
.withDynamicServerList(serverList)
.buildDynamicServerListLoadBalancer(); .buildDynamicServerListLoadBalancer();
return balancer; return balancer;
} }
......
...@@ -16,8 +16,6 @@ ...@@ -16,8 +16,6 @@
package org.springframework.cloud.netflix.zuul; package org.springframework.cloud.netflix.zuul;
import java.util.concurrent.atomic.AtomicReference;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.trace.TraceRepository; import org.springframework.boot.actuate.trace.TraceRepository;
...@@ -25,6 +23,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; ...@@ -25,6 +23,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent; import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
import org.springframework.cloud.client.discovery.event.HeartbeatMonitor;
import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent; import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent;
import org.springframework.cloud.client.discovery.event.ParentHeartbeatEvent; import org.springframework.cloud.client.discovery.event.ParentHeartbeatEvent;
import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent; import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
...@@ -121,7 +120,7 @@ public class ZuulProxyConfiguration extends ZuulConfiguration { ...@@ -121,7 +120,7 @@ public class ZuulProxyConfiguration extends ZuulConfiguration {
private static class ZuulRefreshListener implements private static class ZuulRefreshListener implements
ApplicationListener<ApplicationEvent> { ApplicationListener<ApplicationEvent> {
private AtomicReference<Object> latestHeartbeat = new AtomicReference<>(); private HeartbeatMonitor monitor = new HeartbeatMonitor();
@Autowired @Autowired
private ProxyRouteLocator routeLocator; private ProxyRouteLocator routeLocator;
...@@ -148,9 +147,7 @@ public class ZuulProxyConfiguration extends ZuulConfiguration { ...@@ -148,9 +147,7 @@ public class ZuulProxyConfiguration extends ZuulConfiguration {
} }
private void resetIfNeeded(Object value) { private void resetIfNeeded(Object value) {
if (this.latestHeartbeat.get() == null if (this.monitor.update(value)) {
|| !this.latestHeartbeat.get().equals(value)) {
this.latestHeartbeat.set(value);
reset(); reset();
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment