Close meter registries early in the shutdown process

Closes gh-38240
This commit is contained in:
Moritz Halbritter 2023-11-16 09:05:14 +01:00
parent 50bce029e2
commit d8ce901011
2 changed files with 51 additions and 0 deletions

View File

@ -16,8 +16,11 @@
package org.springframework.boot.actuate.autoconfigure.metrics; package org.springframework.boot.actuate.autoconfigure.metrics;
import java.util.List;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.MeterBinder; import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.instrument.config.MeterFilter; 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.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
/** /**
@ -36,6 +41,7 @@ import org.springframework.core.annotation.Order;
* *
* @author Jon Schneider * @author Jon Schneider
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Moritz Halbritter
* @since 2.0.0 * @since 2.0.0
*/ */
@AutoConfiguration(before = CompositeMeterRegistryAutoConfiguration.class) @AutoConfiguration(before = CompositeMeterRegistryAutoConfiguration.class)
@ -64,4 +70,32 @@ public class MetricsAutoConfiguration {
return new PropertiesMeterFilter(properties); return new PropertiesMeterFilter(properties);
} }
@Bean
MeterRegistryCloser meterRegistryCloser(ObjectProvider<MeterRegistry> 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<ContextClosedEvent> {
private final List<MeterRegistry> meterRegistries;
MeterRegistryCloser(List<MeterRegistry> meterRegistries) {
this.meterRegistries = meterRegistries;
}
@Override
public void onApplicationEvent(ContextClosedEvent event) {
for (MeterRegistry meterRegistry : this.meterRegistries) {
if (!meterRegistry.isClosed()) {
meterRegistry.close();
}
}
}
}
} }

View File

@ -25,6 +25,7 @@ import io.micrometer.core.instrument.config.MeterFilterReply;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.junit.jupiter.api.Test; 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.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -40,6 +41,7 @@ import static org.mockito.Mockito.mock;
* Tests for {@link MetricsAutoConfiguration}. * Tests for {@link MetricsAutoConfiguration}.
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Moritz Halbritter
*/ */
class MetricsAutoConfigurationTests { 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) @Configuration(proxyBeanMethods = false)
static class CustomClockConfiguration { static class CustomClockConfiguration {