Merge branch '2.1.x'

This commit is contained in:
Ryan Baxter
2022-02-09 19:54:50 -05:00
4 changed files with 162 additions and 0 deletions

View File

@@ -28,7 +28,10 @@ import io.github.resilience4j.micrometer.tagged.TaggedCircuitBreakerMetrics;
import io.github.resilience4j.micrometer.tagged.TaggedCircuitBreakerMetricsPublisher;
import io.github.resilience4j.micrometer.tagged.TaggedThreadPoolBulkheadMetrics;
import io.github.resilience4j.timelimiter.TimeLimiterRegistry;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.config.MeterFilter;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
@@ -36,6 +39,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.context.annotation.Bean;
@@ -47,6 +51,7 @@ import org.springframework.context.annotation.Configuration;
* @author Andrii Bohutskyi
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(Resilience4JConfigurationProperties.class)
@ConditionalOnProperty(name = { "spring.cloud.circuitbreaker.resilience4j.enabled",
"spring.cloud.circuitbreaker.resilience4j.blocking.enabled" }, matchIfMissing = true)
public class Resilience4JAutoConfiguration {
@@ -84,6 +89,31 @@ public class Resilience4JAutoConfiguration {
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean({ MeterRegistry.class })
public static class MicrometerResilience4JGroupCustomizerConfiguration {
private static final String RESILIENCE4J_METER_PREFIX = "resilience4j";
@Bean
@ConditionalOnProperty(value = "spring.cloud.circuitbreaker.resilience4j.enableGroupMeterFilter",
havingValue = "true", matchIfMissing = true)
MeterFilter resilience4JMeterFilter(Resilience4JConfigurationProperties properties) {
return new MeterFilter() {
@Override
public Meter.Id map(Meter.Id id) {
if (id.getName().startsWith(RESILIENCE4J_METER_PREFIX)
&& id.getTag(Resilience4JCircuitBreaker.CIRCUIT_BREAKER_GROUP_TAG) == null) {
return id.withTag(Tag.of(Resilience4JCircuitBreaker.CIRCUIT_BREAKER_GROUP_TAG,
properties.getDefaultGroupTag()));
}
return id;
}
};
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean({ MeterRegistry.class })
@ConditionalOnClass(name = { "io.github.resilience4j.micrometer.tagged.TaggedCircuitBreakerMetrics",

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.circuitbreaker.resilience4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Ryan Baxter
*/
@ConfigurationProperties("spring.cloud.circuitbreaker.resilience4j")
public class Resilience4JConfigurationProperties {
private boolean enableGroupMeterFilter = true;
private String defaultGroupTag = "none";
public boolean isEnableGroupMeterFilter() {
return enableGroupMeterFilter;
}
public void setEnableGroupMeterFilter(boolean enableGroupMeterFilter) {
this.enableGroupMeterFilter = enableGroupMeterFilter;
}
public String getDefaultGroupTag() {
return defaultGroupTag;
}
public void setDefaultGroupTag(String defaultGroupTag) {
this.defaultGroupTag = defaultGroupTag;
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.circuitbreaker.resilience4j;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.timelimiter.TimeLimiterRegistry;
import org.junit.Test;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.spy;
/**
* @author Ryan Baxter
*/
public class Resilience4JAutoConfigurationTests {
static Resilience4JCircuitBreakerFactory circuitBreakerFactory = spy(new Resilience4JCircuitBreakerFactory(
CircuitBreakerRegistry.ofDefaults(), TimeLimiterRegistry.ofDefaults(), null));
@Test
public void meterFilterEnabled() {
try (ConfigurableApplicationContext context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.sources(Resilience4JAutoConfigurationTests.TestApp.class).run()) {
assertThat(context.getBean("resilience4JMeterFilter")).isNotNull();
}
}
@Test
public void meterFilterDisabled() {
try (ConfigurableApplicationContext context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.sources(Resilience4JAutoConfigurationTests.TestApp.class)
.properties("spring.cloud.circuitbreaker.resilience4j.enableGroupMeterFilter=false").run()) {
assertThat(context.containsBean("resilience4JMeterFilter")).isFalse();
}
}
@SpringBootConfiguration
@EnableAutoConfiguration
protected static class TestApp {
@Bean
Resilience4JCircuitBreakerFactory circuitBreakerFactory() {
return circuitBreakerFactory;
}
}
}

View File

@@ -17,6 +17,8 @@
package org.springframework.cloud.circuitbreaker.resilience4j;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@@ -87,6 +89,9 @@ public class Resilience4JBulkheadIntegrationTest {
@Autowired
Application.DemoControllerService service;
@Autowired
private TestRestTemplate rest;
@Test
public void testSlow() {
assertThat(service.slow()).isEqualTo("fallback");
@@ -132,6 +137,17 @@ public class Resilience4JBulkheadIntegrationTest {
verify(Application.slowThreadPoolRejectedConsumer, times(1)).consumeEvent(any());
}
@Test
public void testResilience4JMetricsAvailable() {
assertThat(service.normal()).isEqualTo("normal");
assertThat(((List) rest.getForObject("/actuator/metrics", Map.class).get("names"))
.contains("resilience4j.bulkhead.max.thread.pool.size")).isTrue();
assertThat(((List) rest
.getForObject("/actuator/metrics/resilience4j.bulkhead.max.thread.pool.size?tag=group:none", Map.class)
.get("availableTags"))).hasSize(1);
}
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@RestController