Skip to content

Commit f62c118

Browse files
mhalbritterphilwebb
andcommitted
Close meter registries early in the shutdown process
Closes gh-38240 Co-authored-by: Phillip Webb <pwebb@vmware.com>
1 parent d6f67b0 commit f62c118

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java

+47
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.metrics;
1818

19+
import java.util.List;
20+
1921
import io.micrometer.core.annotation.Timed;
2022
import io.micrometer.core.instrument.Clock;
23+
import io.micrometer.core.instrument.MeterRegistry;
2124
import io.micrometer.core.instrument.binder.MeterBinder;
2225
import io.micrometer.core.instrument.config.MeterFilter;
2326

@@ -28,6 +31,7 @@
2831
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2932
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3033
import org.springframework.context.ApplicationContext;
34+
import org.springframework.context.SmartLifecycle;
3135
import org.springframework.context.annotation.Bean;
3236
import org.springframework.core.annotation.Order;
3337

@@ -36,6 +40,8 @@
3640
*
3741
* @author Jon Schneider
3842
* @author Stephane Nicoll
43+
* @author Phil Webb
44+
* @author Moritz Halbritter
3945
* @since 2.0.0
4046
*/
4147
@AutoConfiguration(before = CompositeMeterRegistryAutoConfiguration.class)
@@ -64,4 +70,45 @@ public PropertiesMeterFilter propertiesMeterFilter(MetricsProperties properties)
6470
return new PropertiesMeterFilter(properties);
6571
}
6672

73+
@Bean
74+
MeterRegistryLifecycle meterRegistryLifecycle(ObjectProvider<MeterRegistry> meterRegistries) {
75+
return new MeterRegistryLifecycle(meterRegistries.orderedStream().toList());
76+
}
77+
78+
/**
79+
* Ensures that {@link MeterRegistry meter registries} are closed early in the
80+
* shutdown process.
81+
*/
82+
static class MeterRegistryLifecycle implements SmartLifecycle {
83+
84+
private volatile boolean running;
85+
86+
private final List<MeterRegistry> meterRegistries;
87+
88+
MeterRegistryLifecycle(List<MeterRegistry> meterRegistries) {
89+
this.meterRegistries = meterRegistries;
90+
}
91+
92+
@Override
93+
public void start() {
94+
this.running = true;
95+
}
96+
97+
@Override
98+
public void stop() {
99+
this.running = false;
100+
this.meterRegistries.forEach((registry) -> {
101+
if (!registry.isClosed()) {
102+
registry.close();
103+
}
104+
});
105+
}
106+
107+
@Override
108+
public boolean isRunning() {
109+
return this.running;
110+
}
111+
112+
}
113+
67114
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java

+20
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,19 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.metrics;
1818

19+
import java.util.List;
20+
1921
import io.micrometer.core.instrument.Clock;
2022
import io.micrometer.core.instrument.Meter;
2123
import io.micrometer.core.instrument.MeterRegistry;
2224
import io.micrometer.core.instrument.binder.MeterBinder;
25+
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
2326
import io.micrometer.core.instrument.config.MeterFilter;
2427
import io.micrometer.core.instrument.config.MeterFilterReply;
2528
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
2629
import org.junit.jupiter.api.Test;
2730

31+
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration.MeterRegistryLifecycle;
2832
import org.springframework.boot.autoconfigure.AutoConfigurations;
2933
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
3034
import org.springframework.context.annotation.Bean;
@@ -40,6 +44,7 @@
4044
* Tests for {@link MetricsAutoConfiguration}.
4145
*
4246
* @author Andy Wilkinson
47+
* @author Moritz Halbritter
4348
*/
4449
class MetricsAutoConfigurationTests {
4550

@@ -72,6 +77,21 @@ void configuresMeterRegistries() {
7277
});
7378
}
7479

80+
@Test
81+
void shouldSupplyMeterRegistryLifecycle() {
82+
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(MeterRegistryLifecycle.class));
83+
}
84+
85+
@Test
86+
void meterRegistryLifecycleShouldCloseRegistryOnShutdown() {
87+
MeterRegistry meterRegistry = new CompositeMeterRegistry();
88+
assertThat(meterRegistry.isClosed()).isFalse();
89+
MeterRegistryLifecycle lifecycle = new MeterRegistryLifecycle(List.of(meterRegistry));
90+
lifecycle.start();
91+
lifecycle.stop();
92+
assertThat(meterRegistry.isClosed()).isTrue();
93+
}
94+
7595
@Configuration(proxyBeanMethods = false)
7696
static class CustomClockConfiguration {
7797

0 commit comments

Comments
 (0)