Close meter registries early in the shutdown process

Closes gh-38240

Co-authored-by: Phillip Webb <pwebb@vmware.com>
This commit is contained in:
Moritz Halbritter
2023-11-15 10:12:11 +01:00
parent d6f67b02f7
commit f62c1188a1
2 changed files with 67 additions and 0 deletions

View File

@@ -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,6 +31,7 @@ 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.SmartLifecycle;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
@@ -36,6 +40,8 @@ import org.springframework.core.annotation.Order;
*
* @author Jon Schneider
* @author Stephane Nicoll
* @author Phil Webb
* @author Moritz Halbritter
* @since 2.0.0
*/
@AutoConfiguration(before = CompositeMeterRegistryAutoConfiguration.class)
@@ -64,4 +70,45 @@ public class MetricsAutoConfiguration {
return new PropertiesMeterFilter(properties);
}
@Bean
MeterRegistryLifecycle meterRegistryLifecycle(ObjectProvider<MeterRegistry> meterRegistries) {
return new MeterRegistryLifecycle(meterRegistries.orderedStream().toList());
}
/**
* Ensures that {@link MeterRegistry meter registries} are closed early in the
* shutdown process.
*/
static class MeterRegistryLifecycle implements SmartLifecycle {
private volatile boolean running;
private final List<MeterRegistry> meterRegistries;
MeterRegistryLifecycle(List<MeterRegistry> meterRegistries) {
this.meterRegistries = meterRegistries;
}
@Override
public void start() {
this.running = true;
}
@Override
public void stop() {
this.running = false;
this.meterRegistries.forEach((registry) -> {
if (!registry.isClosed()) {
registry.close();
}
});
}
@Override
public boolean isRunning() {
return this.running;
}
}
}

View File

@@ -16,15 +16,19 @@
package org.springframework.boot.actuate.autoconfigure.metrics;
import java.util.List;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
import io.micrometer.core.instrument.config.MeterFilter;
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.MeterRegistryLifecycle;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
@@ -40,6 +44,7 @@ import static org.mockito.Mockito.mock;
* Tests for {@link MetricsAutoConfiguration}.
*
* @author Andy Wilkinson
* @author Moritz Halbritter
*/
class MetricsAutoConfigurationTests {
@@ -72,6 +77,21 @@ class MetricsAutoConfigurationTests {
});
}
@Test
void shouldSupplyMeterRegistryLifecycle() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(MeterRegistryLifecycle.class));
}
@Test
void meterRegistryLifecycleShouldCloseRegistryOnShutdown() {
MeterRegistry meterRegistry = new CompositeMeterRegistry();
assertThat(meterRegistry.isClosed()).isFalse();
MeterRegistryLifecycle lifecycle = new MeterRegistryLifecycle(List.of(meterRegistry));
lifecycle.start();
lifecycle.stop();
assertThat(meterRegistry.isClosed()).isTrue();
}
@Configuration(proxyBeanMethods = false)
static class CustomClockConfiguration {