From d98bfdea3763a674fb7d1c73dee0c46abbe1a589 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 24 Feb 2014 11:32:27 +0000 Subject: [PATCH] Make sure metricsExecutor is shutdown cleanly The default executor for publishing metrics was a single thread (native JDK) ExecutorService with a non-daemon thread. Changed it to a Spring-managed thread pool of size 1, which is then shutdown with e ApplicationContext automatically. Fixes gh-388 --- .../MetricRepositoryAutoConfiguration.java | 13 ++++++++++--- .../MetricRepositoryAutoConfigurationTests.java | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfiguration.java index 5c78d6d7ee..89f21e9b3f 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfiguration.java @@ -18,7 +18,6 @@ package org.springframework.boot.actuate.autoconfigure; import java.util.List; import java.util.concurrent.Executor; -import java.util.concurrent.Executors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -44,6 +43,7 @@ import org.springframework.context.annotation.Primary; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.SubscribableChannel; import org.springframework.messaging.support.ExecutorSubscribableChannel; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import com.codahale.metrics.MetricRegistry; @@ -121,9 +121,9 @@ public class MetricRepositoryAutoConfiguration { @ConditionalOnClass(MessageChannel.class) static class MetricsChannelConfiguration { - @Autowired(required = false) + @Autowired @Qualifier("metricsExecutor") - private final Executor executor = Executors.newSingleThreadExecutor(); + private Executor executor; @Bean @ConditionalOnMissingBean(name = "metricsChannel") @@ -131,6 +131,13 @@ public class MetricRepositoryAutoConfiguration { return new ExecutorSubscribableChannel(this.executor); } + @Bean + @ConditionalOnMissingBean(name = "metricsExecutor") + protected Executor metricsExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + return executor; + } + @Bean @Primary @ConditionalOnMissingBean(name = "primaryMetricWriter") diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfigurationTests.java index 8af794e011..32fc052207 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfigurationTests.java @@ -30,6 +30,8 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.SyncTaskExecutor; +import org.springframework.messaging.support.ExecutorSubscribableChannel; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import com.codahale.metrics.Gauge; import com.codahale.metrics.MetricRegistry; @@ -38,6 +40,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -50,6 +53,17 @@ import static org.mockito.Mockito.verify; */ public class MetricRepositoryAutoConfigurationTests { + @Test + public void defaultExecutor() throws Exception { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( + MetricRepositoryAutoConfiguration.class); + ExecutorSubscribableChannel channel = context + .getBean(ExecutorSubscribableChannel.class); + ThreadPoolTaskExecutor executor = (ThreadPoolTaskExecutor) channel.getExecutor(); + context.close(); + assertTrue(executor.getThreadPoolExecutor().isShutdown()); + } + @Test public void createServices() throws Exception { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(