Commit ea4ea4a5 by Spencer Gibb

proxy DiscoveryHeartbeatEvent's from parent to child be publishing a…

proxy DiscoveryHeartbeatEvent's from parent to child be publishing a EurekaHeartbeatEvent and having zuul listen for EurekaHeartbeatEvent as well. fixes gh-171
parent f18aeab8
...@@ -22,8 +22,12 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -22,8 +22,12 @@ 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.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.builder.ParentContextApplicationContextInitializer;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.DiscoveryHeartbeatEvent;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -32,6 +36,9 @@ import com.netflix.discovery.EurekaClientConfig; ...@@ -32,6 +36,9 @@ import com.netflix.discovery.EurekaClientConfig;
import com.netflix.discovery.converters.JsonXStream; import com.netflix.discovery.converters.JsonXStream;
import com.netflix.discovery.converters.XmlXStream; import com.netflix.discovery.converters.XmlXStream;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/** /**
* @author Dave Syer * @author Dave Syer
*/ */
...@@ -39,17 +46,19 @@ import com.netflix.discovery.converters.XmlXStream; ...@@ -39,17 +46,19 @@ import com.netflix.discovery.converters.XmlXStream;
@EnableConfigurationProperties @EnableConfigurationProperties
@ConditionalOnClass(EurekaClientConfig.class) @ConditionalOnClass(EurekaClientConfig.class)
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true) @ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
public class EurekaClientAutoConfiguration { public class EurekaClientAutoConfiguration implements ApplicationListener<ParentContextApplicationContextInitializer.ParentContextAvailableEvent> {
@Autowired @Autowired
private ApplicationContext context; private ApplicationContext applicationContext;
private static final ConcurrentMap<String, String> listenerAdded = new ConcurrentHashMap<>();
@PostConstruct @PostConstruct
public void init() { public void init() {
XmlXStream.getInstance().setMarshallingStrategy( XmlXStream.getInstance().setMarshallingStrategy(
new DataCenterAwareMarshallingStrategy(this.context)); new DataCenterAwareMarshallingStrategy(this.applicationContext));
JsonXStream.getInstance().setMarshallingStrategy( JsonXStream.getInstance().setMarshallingStrategy(
new DataCenterAwareMarshallingStrategy(this.context)); new DataCenterAwareMarshallingStrategy(this.applicationContext));
} }
@Bean @Bean
...@@ -64,4 +73,29 @@ public class EurekaClientAutoConfiguration { ...@@ -64,4 +73,29 @@ public class EurekaClientAutoConfiguration {
return new EurekaInstanceConfigBean(); return new EurekaInstanceConfigBean();
} }
/**
* propagate DiscoveryHeartbeatEvent from parent to child.
* Do it via a EurekaHeartbeatEvent since events get published to the
* parent context, otherwise results in a stack overflow
* @param event
*/
@Override
public void onApplicationEvent(final ParentContextApplicationContextInitializer.ParentContextAvailableEvent event) {
final ConfigurableApplicationContext context = event.getApplicationContext();
String childId = context.getId();
ApplicationContext parent = context.getParent();
if (parent != null && "bootstrap".equals(parent.getId())
&& parent instanceof ConfigurableApplicationContext) {
if (listenerAdded.putIfAbsent(childId, childId) == null) {
ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) parent;
ctx.addApplicationListener(new ApplicationListener<DiscoveryHeartbeatEvent>() {
@Override
public void onApplicationEvent(DiscoveryHeartbeatEvent dhe) {
context.publishEvent(new EurekaHeartbeatEvent(dhe));
}
});
}
}
}
} }
...@@ -94,11 +94,14 @@ public class EurekaDiscoveryClientConfiguration implements SmartLifecycle, Order ...@@ -94,11 +94,14 @@ public class EurekaDiscoveryClientConfiguration implements SmartLifecycle, Order
if (jerseyClientField != null) { if (jerseyClientField != null) {
try { try {
jerseyClientField.setAccessible(true); jerseyClientField.setAccessible(true);
Object obj = jerseyClientField.get(DiscoveryManager.getInstance() if (DiscoveryManager.getInstance() != null &&
.getDiscoveryClient()); DiscoveryManager.getInstance().getDiscoveryClient() != null) {
if (obj != null) { Object obj = jerseyClientField.get(DiscoveryManager.getInstance()
EurekaJerseyClient.JerseyClient jerseyClient = (EurekaJerseyClient.JerseyClient) obj; .getDiscoveryClient());
jerseyClient.destroyResources(); if (obj != null) {
EurekaJerseyClient.JerseyClient jerseyClient = (EurekaJerseyClient.JerseyClient) obj;
jerseyClient.destroyResources();
}
} }
} }
catch (Exception ex) { catch (Exception ex) {
......
package org.springframework.cloud.netflix.eureka;
import org.springframework.cloud.client.discovery.DiscoveryHeartbeatEvent;
import org.springframework.context.ApplicationEvent;
/**
* Specifically used when eureka is in the parent bootstrap context to relay the DiscoveryHeartbeatEvent to the child. Avoids stack overflow
* @author Spencer Gibb
*/
public class EurekaHeartbeatEvent extends ApplicationEvent {
private final Object value;
public EurekaHeartbeatEvent(DiscoveryHeartbeatEvent e) {
super(e.getSource());
value = e.getValue();
}
public Object getValue() {
return value;
}
}
...@@ -26,6 +26,7 @@ import org.springframework.cloud.client.discovery.DiscoveryClient; ...@@ -26,6 +26,7 @@ import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.DiscoveryHeartbeatEvent; import org.springframework.cloud.client.discovery.DiscoveryHeartbeatEvent;
import org.springframework.cloud.client.discovery.InstanceRegisteredEvent; import org.springframework.cloud.client.discovery.InstanceRegisteredEvent;
import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent; import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
import org.springframework.cloud.netflix.eureka.EurekaHeartbeatEvent;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory; import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper; import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
import org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter; import org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter;
...@@ -126,17 +127,25 @@ public class ZuulProxyConfiguration extends ZuulConfiguration { ...@@ -126,17 +127,25 @@ public class ZuulProxyConfiguration extends ZuulConfiguration {
|| event instanceof RoutesRefreshedEvent) { || event instanceof RoutesRefreshedEvent) {
reset(); reset();
} }
else if (event instanceof EurekaHeartbeatEvent) {
EurekaHeartbeatEvent e = (EurekaHeartbeatEvent) event;
resetIfNeeded(e.getValue());
}
else if (event instanceof DiscoveryHeartbeatEvent) { else if (event instanceof DiscoveryHeartbeatEvent) {
DiscoveryHeartbeatEvent e = (DiscoveryHeartbeatEvent) event; DiscoveryHeartbeatEvent e = (DiscoveryHeartbeatEvent) event;
if (this.latestHeartbeat.get() == null resetIfNeeded(e.getValue());
|| !this.latestHeartbeat.get().equals(e.getValue())) {
this.latestHeartbeat.set(e.getValue());
reset();
}
} }
} }
private void resetIfNeeded(Object value) {
if (this.latestHeartbeat.get() == null
|| !this.latestHeartbeat.get().equals(value)) {
this.latestHeartbeat.set(value);
reset();
}
}
private void reset() { private void reset() {
this.routeLocator.resetRoutes(); this.routeLocator.resetRoutes();
this.zuulHandlerMapping.registerHandlers(); this.zuulHandlerMapping.registerHandlers();
......
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