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;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.builder.ParentContextApplicationContextInitializer;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.DiscoveryHeartbeatEvent;
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.Configuration;
......@@ -32,6 +36,9 @@ import com.netflix.discovery.EurekaClientConfig;
import com.netflix.discovery.converters.JsonXStream;
import com.netflix.discovery.converters.XmlXStream;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* @author Dave Syer
*/
......@@ -39,17 +46,19 @@ import com.netflix.discovery.converters.XmlXStream;
@EnableConfigurationProperties
@ConditionalOnClass(EurekaClientConfig.class)
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
public class EurekaClientAutoConfiguration {
public class EurekaClientAutoConfiguration implements ApplicationListener<ParentContextApplicationContextInitializer.ParentContextAvailableEvent> {
@Autowired
private ApplicationContext context;
private ApplicationContext applicationContext;
private static final ConcurrentMap<String, String> listenerAdded = new ConcurrentHashMap<>();
@PostConstruct
public void init() {
XmlXStream.getInstance().setMarshallingStrategy(
new DataCenterAwareMarshallingStrategy(this.context));
new DataCenterAwareMarshallingStrategy(this.applicationContext));
JsonXStream.getInstance().setMarshallingStrategy(
new DataCenterAwareMarshallingStrategy(this.context));
new DataCenterAwareMarshallingStrategy(this.applicationContext));
}
@Bean
......@@ -64,4 +73,29 @@ public class EurekaClientAutoConfiguration {
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
if (jerseyClientField != null) {
try {
jerseyClientField.setAccessible(true);
Object obj = jerseyClientField.get(DiscoveryManager.getInstance()
.getDiscoveryClient());
if (obj != null) {
EurekaJerseyClient.JerseyClient jerseyClient = (EurekaJerseyClient.JerseyClient) obj;
jerseyClient.destroyResources();
if (DiscoveryManager.getInstance() != null &&
DiscoveryManager.getInstance().getDiscoveryClient() != null) {
Object obj = jerseyClientField.get(DiscoveryManager.getInstance()
.getDiscoveryClient());
if (obj != null) {
EurekaJerseyClient.JerseyClient jerseyClient = (EurekaJerseyClient.JerseyClient) obj;
jerseyClient.destroyResources();
}
}
}
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;
import org.springframework.cloud.client.discovery.DiscoveryHeartbeatEvent;
import org.springframework.cloud.client.discovery.InstanceRegisteredEvent;
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.zuul.filters.ProxyRequestHelper;
import org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter;
......@@ -126,17 +127,25 @@ public class ZuulProxyConfiguration extends ZuulConfiguration {
|| event instanceof RoutesRefreshedEvent) {
reset();
}
else if (event instanceof EurekaHeartbeatEvent) {
EurekaHeartbeatEvent e = (EurekaHeartbeatEvent) event;
resetIfNeeded(e.getValue());
}
else if (event instanceof DiscoveryHeartbeatEvent) {
DiscoveryHeartbeatEvent e = (DiscoveryHeartbeatEvent) event;
if (this.latestHeartbeat.get() == null
|| !this.latestHeartbeat.get().equals(e.getValue())) {
this.latestHeartbeat.set(e.getValue());
reset();
}
resetIfNeeded(e.getValue());
}
}
private void resetIfNeeded(Object value) {
if (this.latestHeartbeat.get() == null
|| !this.latestHeartbeat.get().equals(value)) {
this.latestHeartbeat.set(value);
reset();
}
}
private void reset() {
this.routeLocator.resetRoutes();
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