Commit 21eb52fa by Dave Syer

Ensure server port is registered late enough with Eureka server

Because we were using Lifecycle to kick off the eureka registration the local server port wasn't available yet. The change is to use an ApplicationListener and listen for the event that contains the container with its port instead. Fixes gh-15
parent f41edfd4
require 'asciidoctor'
require 'erb'
options = {:mkdirs => true, :safe => :unsafe, :attributes => 'linkcss'}
guard 'shell' do
watch(/^[A-Za-z].*\.adoc$/) {|m|
Asciidoctor.render_file('src/main/adoc/README.adoc', options.merge(:to_file => './README.md'))
Asciidoctor.render_file('src/main/adoc/spring-cloud-netflix.adoc', options.merge(:to_dir => 'target/docs'))
}
end
...@@ -108,6 +108,11 @@ ...@@ -108,6 +108,11 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-cypher-compiler-2.1</artifactId>
<version>2.1.2</version>
</dependency>
</dependencies> </dependencies>
</project> </project>
...@@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; ...@@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
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.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.servo.ServoMetricReader; import org.springframework.cloud.netflix.servo.ServoMetricReader;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
...@@ -34,7 +35,6 @@ import org.springframework.context.annotation.Configuration; ...@@ -34,7 +35,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import com.netflix.appinfo.ApplicationInfoManager; import com.netflix.appinfo.ApplicationInfoManager;
...@@ -54,8 +54,7 @@ import com.netflix.discovery.EurekaClientConfig; ...@@ -54,8 +54,7 @@ import com.netflix.discovery.EurekaClientConfig;
EurekaInstanceConfigBean.class }) EurekaInstanceConfigBean.class })
@ConditionalOnClass(EurekaClientConfig.class) @ConditionalOnClass(EurekaClientConfig.class)
@ConditionalOnExpression("${eureka.client.enabled:true}") @ConditionalOnExpression("${eureka.client.enabled:true}")
public class EurekaClientConfiguration implements public class EurekaClientConfiguration implements SmartLifecycle, Ordered {
ApplicationListener<ContextRefreshedEvent>, SmartLifecycle, Ordered {
private static final Logger logger = LoggerFactory private static final Logger logger = LoggerFactory
.getLogger(EurekaClientConfiguration.class); .getLogger(EurekaClientConfiguration.class);
...@@ -64,19 +63,14 @@ public class EurekaClientConfiguration implements ...@@ -64,19 +63,14 @@ public class EurekaClientConfiguration implements
private int order = 0; private int order = 0;
private int port = 0;
@Autowired @Autowired
private EurekaClientConfigBean clientConfig; private EurekaClientConfigBean clientConfig;
@Autowired @Autowired
private EurekaInstanceConfigBean instanceConfig; private EurekaInstanceConfigBean instanceConfig;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
logger.info("Registering application {} with eureka with status UP",
instanceConfig.getAppname());
ApplicationInfoManager.getInstance().setInstanceStatus(InstanceStatus.UP);
}
@PreDestroy @PreDestroy
public void close() { public void close() {
logger.info("Removing application {} from eureka", instanceConfig.getAppname()); logger.info("Removing application {} from eureka", instanceConfig.getAppname());
...@@ -85,11 +79,20 @@ public class EurekaClientConfiguration implements ...@@ -85,11 +79,20 @@ public class EurekaClientConfiguration implements
@Override @Override
public void start() { public void start() {
if (port != 0) {
instanceConfig.setNonSecurePort(port);
DiscoveryManager.getInstance().initComponent(instanceConfig, clientConfig); DiscoveryManager.getInstance().initComponent(instanceConfig, clientConfig);
logger.info("Registering application {} with eureka with status UP",
instanceConfig.getAppname());
ApplicationInfoManager.getInstance().setInstanceStatus(InstanceStatus.UP);
}
} }
@Override @Override
public void stop() { public void stop() {
logger.info("Unregistering application {} with eureka with status OUT_OF_SERVICE",
instanceConfig.getAppname());
ApplicationInfoManager.getInstance().setInstanceStatus(InstanceStatus.OUT_OF_SERVICE);
running = false; running = false;
} }
...@@ -134,4 +137,18 @@ public class EurekaClientConfiguration implements ...@@ -134,4 +137,18 @@ public class EurekaClientConfiguration implements
new ServoMetricReader(server), config); new ServoMetricReader(server), config);
} }
@Bean
protected ApplicationListener<EmbeddedServletContainerInitializedEvent> containerPortInitializer() {
return new ApplicationListener<EmbeddedServletContainerInitializedEvent>() {
@Override
public void onApplicationEvent(EmbeddedServletContainerInitializedEvent event) {
// TODO: take SSL into account when Spring Boot 1.2 is available
EurekaClientConfiguration.this.port = event.getEmbeddedServletContainer()
.getPort();
EurekaClientConfiguration.this.start();
}
};
}
} }
= Spring Cloud Netflix
This project provides Netflix OSS integrations for Spring Boot apps through autoconfiguration
and binding to the Spring Environment and other Spring programming model idioms.
== Service Discovery: Eureka Clients
Example eureka client:
```
@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableEurekaClient
@RestController
public class Application {
@RequestMapping("/")
public String home() {
return "Hello world";
}
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
```
(i.e. utterly normal Spring Boot app). Configuration is required to locate the Eureka server. Example:
```
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8080/v2/
default.defaultZone: http://localhost:8080/v2/
```
The default application name, virtual host and non-secure port are taken from the `Environment` is
`${spring.application.name}`, `${spring.application.name}.mydomain.net` and `${server.port}` respectively.
== Service Discovery: Eureka Server
Example eureka server:
```
@Configuration
@EnableAutoConfiguration
@EnableEurekaServer
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
```
The server has a home page with a UI, and HTTP API endpoints per the
normal Eureka functionality under `/v2/*`.
Eureka (apache -> tomcat) see https://github.com/cfregly/fluxcapacitor/wiki/NetflixOSS-FAQ#eureka-service-discovery-load-balancer[flux capacitor] and https://groups.google.com/forum/?fromgroups#!topic/eureka_netflix/g3p2r7gHnN0[google group discussion].
== Circuit Breaker: Hystrix Clients
== Circuit Breaker: Hystrix Dashboard
=== Turbine
== Declarative REST Client: Feign
== Client Side Load Balancer: Ribbon
== External Configuration: Archaius
== Router and Filter: Zuul
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