Add health indicators infrastructure
- Adds a generic 'bindersHealthIndicator' bean controlled by `management.health.binders.enabled` that tallies results from binders - Binders are expected to expose one or more health indicators based on the status of the middleware connection. If no health indicators are exposed, the status is deemed to be 'UNKNOWN' - Add support for Redis and Rabbit based on existing health indicators Moved binder health indicator to autoconfiguration Also updated copyright
This commit is contained in:
committed by
Ilayaperumal Gopinathan
parent
a2486db905
commit
7477fcbee9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,9 @@
|
||||
package org.springframework.cloud.stream.binder.rabbit.config;
|
||||
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.RabbitHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration;
|
||||
@@ -66,5 +69,11 @@ public class RabbitServiceAutoConfiguration {
|
||||
@Profile("!cloud")
|
||||
@Import(RabbitAutoConfiguration.class)
|
||||
protected static class NoCloudConfig {
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HealthIndicator binderHealthIndicator(RabbitTemplate rabbitTemplate) {
|
||||
return new RabbitHealthIndicator(rabbitTemplate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,17 @@
|
||||
|
||||
package org.springframework.cloud.stream.binder.rabbit.integration;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.collection.IsMapContaining.hasKey;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.ClassRule;
|
||||
@@ -34,6 +38,9 @@ import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.core.RabbitAdmin;
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.binder.Binder;
|
||||
@@ -73,7 +80,7 @@ public class RabbitBinderModuleTests {
|
||||
|
||||
@Test
|
||||
public void testParentConnectionFactoryInheritedByDefault() {
|
||||
context = SpringApplication.run(SimpleProcessor.class);
|
||||
context = SpringApplication.run(SimpleProcessor.class, "--server.port=0");
|
||||
BinderFactory<?> binderFactory = context.getBean(BinderFactory.class);
|
||||
Binder<?> binder = binderFactory.getBinder(null);
|
||||
assertThat(binder, instanceOf(RabbitMessageChannelBinder.class));
|
||||
@@ -83,11 +90,20 @@ public class RabbitBinderModuleTests {
|
||||
assertThat(binderConnectionFactory, instanceOf(CachingConnectionFactory.class));
|
||||
ConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class);
|
||||
assertThat(binderConnectionFactory, is(connectionFactory));
|
||||
CompositeHealthIndicator bindersHealthIndicator =
|
||||
context.getBean("bindersHealthIndicator", CompositeHealthIndicator.class);
|
||||
DirectFieldAccessor directFieldAccessor = new DirectFieldAccessor(bindersHealthIndicator);
|
||||
assertNotNull(bindersHealthIndicator);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String,HealthIndicator> healthIndicators =
|
||||
(Map<String, HealthIndicator>) directFieldAccessor.getPropertyValue("indicators");
|
||||
assertThat(healthIndicators, hasKey("rabbit"));
|
||||
assertThat(healthIndicators.get("rabbit").health().getStatus(), equalTo(Status.UP));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParentConnectionFactoryInheritedIfOverridden() {
|
||||
context = new SpringApplication(SimpleProcessor.class, ConnectionFactoryConfiguration.class).run();
|
||||
context = new SpringApplication(SimpleProcessor.class, ConnectionFactoryConfiguration.class).run("--server.port=0");
|
||||
BinderFactory<?> binderFactory = context.getBean(BinderFactory.class);
|
||||
Binder<?> binder = binderFactory.getBinder(null);
|
||||
assertThat(binder, instanceOf(RabbitMessageChannelBinder.class));
|
||||
@@ -97,6 +113,16 @@ public class RabbitBinderModuleTests {
|
||||
assertThat(binderConnectionFactory, is(MOCK_CONNECTION_FACTORY));
|
||||
ConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class);
|
||||
assertThat(binderConnectionFactory, is(connectionFactory));
|
||||
CompositeHealthIndicator bindersHealthIndicator =
|
||||
context.getBean("bindersHealthIndicator", CompositeHealthIndicator.class);
|
||||
assertNotNull(bindersHealthIndicator);
|
||||
DirectFieldAccessor directFieldAccessor = new DirectFieldAccessor(bindersHealthIndicator);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String,HealthIndicator> healthIndicators =
|
||||
(Map<String, HealthIndicator>) directFieldAccessor.getPropertyValue("indicators");
|
||||
assertThat(healthIndicators, hasKey("rabbit"));
|
||||
// mock connection factory behaves as if down
|
||||
assertThat(healthIndicators.get("rabbit").health().getStatus(), equalTo(Status.DOWN));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -106,6 +132,7 @@ public class RabbitBinderModuleTests {
|
||||
params.add("--spring.cloud.stream.output.binder=custom");
|
||||
params.add("--spring.cloud.stream.binders.custom.type=rabbit");
|
||||
params.add("--spring.cloud.stream.binders.custom.environment.foo=bar");
|
||||
params.add("--server.port=0");
|
||||
context = SpringApplication.run(SimpleProcessor.class, params.toArray(new String[params.size()]));
|
||||
BinderFactory<?> binderFactory = context.getBean(BinderFactory.class);
|
||||
Binder<?> binder = binderFactory.getBinder(null);
|
||||
@@ -115,6 +142,15 @@ public class RabbitBinderModuleTests {
|
||||
(ConnectionFactory) binderFieldAccessor.getPropertyValue("connectionFactory");
|
||||
ConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class);
|
||||
assertThat(binderConnectionFactory, not(is(connectionFactory)));
|
||||
CompositeHealthIndicator bindersHealthIndicator =
|
||||
context.getBean("bindersHealthIndicator", CompositeHealthIndicator.class);
|
||||
assertNotNull(bindersHealthIndicator);
|
||||
DirectFieldAccessor directFieldAccessor = new DirectFieldAccessor(bindersHealthIndicator);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String,HealthIndicator> healthIndicators =
|
||||
(Map<String, HealthIndicator>) directFieldAccessor.getPropertyValue("indicators");
|
||||
assertThat(healthIndicators, hasKey("custom"));
|
||||
assertThat(healthIndicators.get("custom").health().getStatus(), equalTo(Status.UP));
|
||||
}
|
||||
|
||||
@EnableBinding(Processor.class)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,7 +18,6 @@ package org.springframework.cloud.stream.binder.redis.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.stream.binder.redis.RedisMessageChannelBinder;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.stream.binder.redis.config;
|
||||
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.RedisHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
@@ -66,4 +68,8 @@ public class RedisServiceAutoConfiguration {
|
||||
protected static class NoCloudConfig {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HealthIndicator binderHealthIndicator(RedisConnectionFactory redisConnectionFactory) {
|
||||
return new RedisHealthIndicator(redisConnectionFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,13 +16,17 @@
|
||||
|
||||
package org.springframework.cloud.stream.binder.redis.integration;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.collection.IsMapContaining.hasKey;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.ClassRule;
|
||||
@@ -31,6 +35,9 @@ import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.binder.Binder;
|
||||
@@ -65,7 +72,7 @@ public class RedisBinderModuleTests {
|
||||
|
||||
@Test
|
||||
public void testParentConnectionFactoryInheritedByDefault() {
|
||||
context = SpringApplication.run(SimpleProcessor.class);
|
||||
context = SpringApplication.run(SimpleProcessor.class, "--server.port=0");
|
||||
BinderFactory<?> binderFactory = context.getBean(BinderFactory.class);
|
||||
Binder<?> binder = binderFactory.getBinder(null);
|
||||
assertThat(binder, instanceOf(RedisMessageChannelBinder.class));
|
||||
@@ -75,6 +82,15 @@ public class RedisBinderModuleTests {
|
||||
assertThat(binderConnectionFactory, instanceOf(RedisConnectionFactory.class));
|
||||
RedisConnectionFactory connectionFactory = context.getBean(RedisConnectionFactory.class);
|
||||
assertThat(binderConnectionFactory, is(connectionFactory));
|
||||
CompositeHealthIndicator bindersHealthIndicator =
|
||||
context.getBean("bindersHealthIndicator", CompositeHealthIndicator.class);
|
||||
assertNotNull(bindersHealthIndicator);
|
||||
DirectFieldAccessor directFieldAccessor = new DirectFieldAccessor(bindersHealthIndicator);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String,HealthIndicator> healthIndicators =
|
||||
(Map<String, HealthIndicator>) directFieldAccessor.getPropertyValue("indicators");
|
||||
assertThat(healthIndicators, hasKey("redis"));
|
||||
assertThat(healthIndicators.get("redis").health().getStatus(), equalTo(Status.UP));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -89,6 +105,15 @@ public class RedisBinderModuleTests {
|
||||
assertThat(binderConnectionFactory, is(MOCK_CONNECTION_FACTORY));
|
||||
RedisConnectionFactory connectionFactory = context.getBean(RedisConnectionFactory.class);
|
||||
assertThat(binderConnectionFactory, is(connectionFactory));
|
||||
CompositeHealthIndicator bindersHealthIndicator =
|
||||
context.getBean("bindersHealthIndicator", CompositeHealthIndicator.class);
|
||||
assertNotNull(bindersHealthIndicator);
|
||||
DirectFieldAccessor directFieldAccessor = new DirectFieldAccessor(bindersHealthIndicator);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String,HealthIndicator> healthIndicators =
|
||||
(Map<String, HealthIndicator>) directFieldAccessor.getPropertyValue("indicators");
|
||||
assertThat(healthIndicators, hasKey("redis"));
|
||||
assertThat(healthIndicators.get("redis").health().getStatus(), equalTo(Status.UP));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -107,6 +132,15 @@ public class RedisBinderModuleTests {
|
||||
(RedisConnectionFactory) binderFieldAccessor.getPropertyValue("connectionFactory");
|
||||
RedisConnectionFactory connectionFactory = context.getBean(RedisConnectionFactory.class);
|
||||
assertThat(binderConnectionFactory, not(is(connectionFactory)));
|
||||
CompositeHealthIndicator bindersHealthIndicator =
|
||||
context.getBean("bindersHealthIndicator", CompositeHealthIndicator.class);
|
||||
assertNotNull(bindersHealthIndicator);
|
||||
DirectFieldAccessor directFieldAccessor = new DirectFieldAccessor(bindersHealthIndicator);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String,HealthIndicator> healthIndicators =
|
||||
(Map<String, HealthIndicator>) directFieldAccessor.getPropertyValue("indicators");
|
||||
assertThat(healthIndicators, hasKey("custom"));
|
||||
assertThat(healthIndicators.get("custom").health().getStatus(), equalTo(Status.UP));
|
||||
}
|
||||
|
||||
@EnableBinding(Processor.class)
|
||||
|
||||
Reference in New Issue
Block a user