From d8ce9010111444250a530e9aaeb718a25074f9b2 Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Thu, 16 Nov 2023 09:05:14 +0100 Subject: [PATCH] Close meter registries early in the shutdown process Closes gh-38240 --- .../metrics/MetricsAutoConfiguration.java | 34 +++++++++++++++++++ .../MetricsAutoConfigurationTests.java | 17 ++++++++++ 2 files changed, 51 insertions(+) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java index 16eaab791d9..dfb7e73a5f6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java @@ -16,8 +16,11 @@ package org.springframework.boot.actuate.autoconfigure.metrics; +import java.util.List; + import io.micrometer.core.annotation.Timed; import io.micrometer.core.instrument.Clock; +import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.binder.MeterBinder; import io.micrometer.core.instrument.config.MeterFilter; @@ -28,7 +31,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.Bean; +import org.springframework.context.event.ContextClosedEvent; import org.springframework.core.annotation.Order; /** @@ -36,6 +41,7 @@ import org.springframework.core.annotation.Order; * * @author Jon Schneider * @author Stephane Nicoll + * @author Moritz Halbritter * @since 2.0.0 */ @AutoConfiguration(before = CompositeMeterRegistryAutoConfiguration.class) @@ -64,4 +70,32 @@ public class MetricsAutoConfiguration { return new PropertiesMeterFilter(properties); } + @Bean + MeterRegistryCloser meterRegistryCloser(ObjectProvider meterRegistries) { + return new MeterRegistryCloser(meterRegistries.orderedStream().toList()); + } + + /** + * Ensures that {@link MeterRegistry meter registries} are closed early in the + * shutdown process. + */ + static class MeterRegistryCloser implements ApplicationListener { + + private final List meterRegistries; + + MeterRegistryCloser(List meterRegistries) { + this.meterRegistries = meterRegistries; + } + + @Override + public void onApplicationEvent(ContextClosedEvent event) { + for (MeterRegistry meterRegistry : this.meterRegistries) { + if (!meterRegistry.isClosed()) { + meterRegistry.close(); + } + } + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java index c04c31435a7..b7f4876bb3f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java @@ -25,6 +25,7 @@ import io.micrometer.core.instrument.config.MeterFilterReply; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.junit.jupiter.api.Test; +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration.MeterRegistryCloser; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; @@ -40,6 +41,7 @@ import static org.mockito.Mockito.mock; * Tests for {@link MetricsAutoConfiguration}. * * @author Andy Wilkinson + * @author Moritz Halbritter */ class MetricsAutoConfigurationTests { @@ -72,6 +74,21 @@ class MetricsAutoConfigurationTests { }); } + @Test + void shouldSupplyMeterRegistryCloser() { + this.contextRunner.run((context) -> assertThat(context).hasSingleBean(MeterRegistryCloser.class)); + } + + @Test + void meterRegistryCloserShouldCloseRegistryOnShutdown() { + this.contextRunner.withUserConfiguration(MeterRegistryConfiguration.class).run((context) -> { + MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); + assertThat(meterRegistry.isClosed()).isFalse(); + context.close(); + assertThat(meterRegistry.isClosed()).isTrue(); + }); + } + @Configuration(proxyBeanMethods = false) static class CustomClockConfiguration {