Skip to content

Commit

Permalink
Support TimeLimiter in spring-cloud and added TimeLimiterConfigCustom…
Browse files Browse the repository at this point in the history
…izer (ReactiveX#840)
  • Loading branch information
dlsrb6342 authored Feb 4, 2020
1 parent 476151a commit fc8cc89
Show file tree
Hide file tree
Showing 25 changed files with 433 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ public interface BulkheadConfigCustomizer extends CustomizerWithName {
* @param instanceName the name of the instance
* @param consumer delegate call to Consumer when {@link BulkheadConfigCustomizer#customize(BulkheadConfig.Builder)}
* is called
* @param <T> generic type of Customizer
* @return Customizer instance
*/
static <T> BulkheadConfigCustomizer of(@NonNull String instanceName,
static BulkheadConfigCustomizer of(@NonNull String instanceName,
@NonNull Consumer<BulkheadConfig.Builder> consumer) {
return new BulkheadConfigCustomizer() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ public interface ThreadPoolBulkheadConfigCustomizer extends CustomizerWithName {
* @param instanceName the name of the instance
* @param consumer delegate call to Consumer when {@link ThreadPoolBulkheadConfigCustomizer#customize(ThreadPoolBulkheadConfig.Builder)}
* is called
* @param <T> generic type of Customizer
* @return Customizer instance
*/
static <T> ThreadPoolBulkheadConfigCustomizer of(@NonNull String instanceName,
static ThreadPoolBulkheadConfigCustomizer of(@NonNull String instanceName,
@NonNull Consumer<ThreadPoolBulkheadConfig.Builder> consumer) {
return new ThreadPoolBulkheadConfigCustomizer() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ public interface CircuitBreakerConfigCustomizer extends CustomizerWithName {
* @param instanceName the name of the instance
* @param consumer delegate call to Consumer when {@link CircuitBreakerConfigCustomizer#customize(CircuitBreakerConfig.Builder)}
* is called
* @param <T> generic type of Customizer
* @return Customizer instance
*/
static <T> CircuitBreakerConfigCustomizer of(@NonNull String instanceName,
static CircuitBreakerConfigCustomizer of(@NonNull String instanceName,
@NonNull Consumer<CircuitBreakerConfig.Builder> consumer) {
return new CircuitBreakerConfigCustomizer() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ public interface RateLimiterConfigCustomizer extends CustomizerWithName {
* @param instanceName the name of the instance
* @param consumer delegate call to Consumer when {@link RateLimiterConfigCustomizer#customize(RateLimiterConfig.Builder)}
* is called
* @param <T> generic type of Customizer
* @return Customizer instance
*/
static <T> RateLimiterConfigCustomizer of(@NonNull String instanceName,
static RateLimiterConfigCustomizer of(@NonNull String instanceName,
@NonNull Consumer<RateLimiterConfig.Builder> consumer) {
return new RateLimiterConfigCustomizer() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ public interface RetryConfigCustomizer extends CustomizerWithName {
* @param instanceName the name of the instance
* @param consumer delegate call to Consumer when {@link RetryConfigCustomizer#customize(RetryConfig.Builder)}
* is called
* @param <T> generic type of Customizer
* @return Customizer instance
*/
static <T> RetryConfigCustomizer of(@NonNull String instanceName,
static RetryConfigCustomizer of(@NonNull String instanceName,
@NonNull Consumer<RetryConfig.Builder> consumer) {
return new RetryConfigCustomizer() {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2020 Ingyu Hwang
*
* 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
*
* http://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 io.github.resilience4j.common.timelimiter.configuration;

import io.github.resilience4j.common.CustomizerWithName;
import io.github.resilience4j.core.lang.NonNull;
import io.github.resilience4j.timelimiter.TimeLimiterConfig;

import java.util.function.Consumer;

/**
* Enable customization time limiter configuration builders programmatically.
*/
public interface TimeLimiterConfigCustomizer extends CustomizerWithName {

/**
* Customize time limiter configuration builder.
*
* @param configBuilder to be customized
*/
void customize(TimeLimiterConfig.Builder configBuilder);

/**
* A convenient method to create TimeLimiterConfigCustomizer using {@link Consumer}
*
* @param instanceName the name of the instance
* @param consumer delegate call to Consumer when {@link TimeLimiterConfigCustomizer#customize(TimeLimiterConfig.Builder)}
* is called
* @return Customizer instance
*/
static TimeLimiterConfigCustomizer of(@NonNull String instanceName,
@NonNull Consumer<TimeLimiterConfig.Builder> consumer) {
return new TimeLimiterConfigCustomizer() {

@Override
public void customize(TimeLimiterConfig.Builder builder) {
consumer.accept(builder);
}

@Override
public String name() {
return instanceName;
}
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
package io.github.resilience4j.common.timelimiter.configuration;

import io.github.resilience4j.common.CommonProperties;
import io.github.resilience4j.common.CompositeCustomizer;
import io.github.resilience4j.common.utils.ConfigUtils;
import io.github.resilience4j.core.ConfigurationNotFoundException;
import io.github.resilience4j.core.StringUtils;
import io.github.resilience4j.core.lang.Nullable;
import io.github.resilience4j.timelimiter.TimeLimiterConfig;

import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
Expand All @@ -50,7 +52,9 @@ public InstanceProperties getInstanceProperties(String backend) {
return instances.get(backend);
}

public TimeLimiterConfig createTimeLimiterConfig(@Nullable InstanceProperties instanceProperties) {
public TimeLimiterConfig createTimeLimiterConfig(String backendName,
@Nullable InstanceProperties instanceProperties,
CompositeCustomizer<TimeLimiterConfigCustomizer> compositeTimeLimiterCustomizer) {
if (instanceProperties == null) {
return TimeLimiterConfig.ofDefaults();
}
Expand All @@ -59,20 +63,28 @@ public TimeLimiterConfig createTimeLimiterConfig(@Nullable InstanceProperties in
if (baseProperties == null) {
throw new ConfigurationNotFoundException(instanceProperties.getBaseConfig());
}
return buildConfigFromBaseConfig(baseProperties, instanceProperties);
return buildConfigFromBaseConfig(baseProperties, instanceProperties,
compositeTimeLimiterCustomizer, backendName);
}
return buildTimeLimiterConfig(TimeLimiterConfig.custom(), instanceProperties);
return buildTimeLimiterConfig(TimeLimiterConfig.custom(), instanceProperties,
compositeTimeLimiterCustomizer, backendName);
}

private static TimeLimiterConfig buildConfigFromBaseConfig(
InstanceProperties baseProperties, InstanceProperties instanceProperties) {
InstanceProperties baseProperties, InstanceProperties instanceProperties,
CompositeCustomizer<TimeLimiterConfigCustomizer> compositeTimeLimiterCustomizer, String backendName) {

ConfigUtils.mergePropertiesIfAny(baseProperties, instanceProperties);
TimeLimiterConfig baseConfig = buildTimeLimiterConfig(TimeLimiterConfig.custom(), baseProperties);
return buildTimeLimiterConfig(TimeLimiterConfig.from(baseConfig), instanceProperties);
TimeLimiterConfig baseConfig = buildTimeLimiterConfig(TimeLimiterConfig.custom(), baseProperties,
compositeTimeLimiterCustomizer, backendName);
return buildTimeLimiterConfig(TimeLimiterConfig.from(baseConfig), instanceProperties,
compositeTimeLimiterCustomizer, backendName);
}

private static TimeLimiterConfig buildTimeLimiterConfig(
TimeLimiterConfig.Builder builder, @Nullable InstanceProperties instanceProperties) {
TimeLimiterConfig.Builder builder, @Nullable InstanceProperties instanceProperties,
CompositeCustomizer<TimeLimiterConfigCustomizer> compositeTimeLimiterCustomizer, String backendName) {

if (instanceProperties == null) {
return builder.build();
}
Expand All @@ -85,11 +97,15 @@ private static TimeLimiterConfig buildTimeLimiterConfig(
builder.cancelRunningFuture(instanceProperties.getCancelRunningFuture());
}

compositeTimeLimiterCustomizer.getCustomizer(backendName).ifPresent(
timeLimiterConfigCustomizer -> timeLimiterConfigCustomizer.customize(builder));

return builder.build();
}

public TimeLimiterConfig createTimeLimiterConfig(String limiter) {
return createTimeLimiterConfig(getInstanceProperties(limiter));
return createTimeLimiterConfig(limiter, getInstanceProperties(limiter),
new CompositeCustomizer<>(Collections.emptyList()));
}

public static class InstanceProperties {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package io.github.resilience4j.common.timelimiter.configuration;

import io.github.resilience4j.common.CompositeCustomizer;
import io.github.resilience4j.core.ConfigurationNotFoundException;
import io.github.resilience4j.timelimiter.TimeLimiterConfig;
import io.vavr.collection.List;
import org.junit.Test;

import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -128,4 +131,17 @@ public void testIllegalArgumentOnTimeoutDuration() {
defaultProperties.setTimeoutDuration(Duration.ofMillis(-1000));
}

@Test
public void testCustomizeTimeLimiterConfig() {
TimeLimiterConfigurationProperties timeLimiterConfigurationProperties = new TimeLimiterConfigurationProperties();
TimeLimiterConfigCustomizer customizer = TimeLimiterConfigCustomizer.of("backend",
builder -> builder.timeoutDuration(Duration.ofSeconds(10)));
TimeLimiterConfigurationProperties.InstanceProperties instanceProperties = new TimeLimiterConfigurationProperties.InstanceProperties();
instanceProperties.setTimeoutDuration(Duration.ofSeconds(3));
TimeLimiterConfig config = timeLimiterConfigurationProperties.createTimeLimiterConfig("backend", instanceProperties,
new CompositeCustomizer<>(Collections.singletonList(customizer)));

assertThat(config).isNotNull();
assertThat(config.getTimeoutDuration()).isEqualTo(Duration.ofSeconds(10));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package io.github.resilience4j.timelimiter.autoconfigure;

import io.github.resilience4j.common.CompositeCustomizer;
import io.github.resilience4j.common.timelimiter.configuration.TimeLimiterConfigCustomizer;
import io.github.resilience4j.consumer.EventConsumerRegistry;
import io.github.resilience4j.core.registry.RegistryEventConsumer;
import io.github.resilience4j.fallback.FallbackDecorators;
Expand All @@ -28,6 +30,7 @@
import io.github.resilience4j.utils.ReactorOnClasspathCondition;
import io.github.resilience4j.utils.RxJava2OnClasspathCondition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.*;

Expand All @@ -43,13 +46,24 @@ protected AbstractTimeLimiterConfigurationOnMissingBean() {
this.timeLimiterConfiguration = new TimeLimiterConfiguration();
}

@Bean
@ConditionalOnMissingBean(name = "compositeTimeLimiterCustomizer")
@Qualifier("compositeTimeLimiterCustomizer")
public CompositeCustomizer<TimeLimiterConfigCustomizer> compositeTimeLimiterCustomizer(
@Autowired(required = false) List<TimeLimiterConfigCustomizer> customizers) {
return new CompositeCustomizer<>(customizers);
}

@Bean
@ConditionalOnMissingBean
public TimeLimiterRegistry timeLimiterRegistry(TimeLimiterConfigurationProperties timeLimiterProperties,
EventConsumerRegistry<TimeLimiterEvent> timeLimiterEventsConsumerRegistry,
RegistryEventConsumer<TimeLimiter> timeLimiterRegistryEventConsumer) {
public TimeLimiterRegistry timeLimiterRegistry(
TimeLimiterConfigurationProperties timeLimiterProperties,
EventConsumerRegistry<TimeLimiterEvent> timeLimiterEventsConsumerRegistry,
RegistryEventConsumer<TimeLimiter> timeLimiterRegistryEventConsumer,
@Qualifier("compositeTimeLimiterCustomizer") CompositeCustomizer<TimeLimiterConfigCustomizer> compositeTimeLimiterCustomizer) {
return timeLimiterConfiguration.timeLimiterRegistry(
timeLimiterProperties, timeLimiterEventsConsumerRegistry, timeLimiterRegistryEventConsumer);
timeLimiterProperties, timeLimiterEventsConsumerRegistry,
timeLimiterRegistryEventConsumer, compositeTimeLimiterCustomizer);
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import io.github.resilience4j.common.bulkhead.configuration.ThreadPoolBulkheadConfigCustomizer;
import io.github.resilience4j.common.bulkhead.configuration.ThreadPoolBulkheadConfigurationProperties;
import io.github.resilience4j.common.circuitbreaker.configuration.CircuitBreakerConfigCustomizer;
import io.github.resilience4j.common.timelimiter.configuration.TimeLimiterConfigCustomizer;
import io.github.resilience4j.consumer.DefaultEventConsumerRegistry;
import io.github.resilience4j.core.registry.CompositeRegistryEventConsumer;
import io.github.resilience4j.fallback.CompletionStageFallbackDecorator;
Expand All @@ -42,6 +43,7 @@
import io.github.resilience4j.timelimiter.configure.TimeLimiterConfigurationProperties;
import org.junit.Test;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.Optional;
Expand Down Expand Up @@ -135,7 +137,10 @@ public void testTimeLimiterCommonConfig() {
assertThat(timeLimiterConfigurationOnMissingBean
.timeLimiterRegistry(new TimeLimiterConfigurationProperties(),
new DefaultEventConsumerRegistry<>(),
new CompositeRegistryEventConsumer<>(Collections.emptyList()))).isNotNull();
new CompositeRegistryEventConsumer<>(Collections.emptyList()),
new CompositeCustomizer<>(Collections.singletonList(
TimeLimiterConfigCustomizer.of("backend", builder -> builder.timeoutDuration(
Duration.ofSeconds(10))))))).isNotNull();
assertThat(timeLimiterConfigurationOnMissingBean
.timeLimiterAspect(new TimeLimiterConfigurationProperties(),
TimeLimiterRegistry.ofDefaults(), Collections.emptyList(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
import io.github.resilience4j.common.circuitbreaker.configuration.CircuitBreakerConfigCustomizer;
import io.github.resilience4j.common.ratelimiter.configuration.RateLimiterConfigCustomizer;
import io.github.resilience4j.common.retry.configuration.RetryConfigCustomizer;
import io.github.resilience4j.common.timelimiter.configuration.TimeLimiterConfigCustomizer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;

import java.time.Duration;
import java.util.List;


Expand Down Expand Up @@ -65,6 +67,13 @@ public RetryConfigCustomizer testRetryCustomizer() {
builder -> builder.maxAttempts(4));
}


@Bean
public TimeLimiterConfigCustomizer testTimeLimiterCustomizer() {
return TimeLimiterConfigCustomizer.of("timeLimiterBackendD",
builder -> builder.timeoutDuration(Duration.ofSeconds(3)));
}

@Bean
public BulkheadConfigCustomizer testBulkheadConfigCustomizer() {
return new BulkheadConfigCustomizer() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package io.github.resilience4j.timelimiter;

import com.github.tomakehurst.wiremock.junit.WireMockRule;
import io.github.resilience4j.common.CompositeCustomizer;
import io.github.resilience4j.common.timelimiter.configuration.TimeLimiterConfigCustomizer;
import io.github.resilience4j.common.timelimiter.monitoring.endpoint.TimeLimiterEventsEndpointResponse;
import io.github.resilience4j.service.test.DummyService;
import io.github.resilience4j.service.test.TestApplication;
Expand Down Expand Up @@ -33,6 +35,9 @@ public class TimeLimiterAutoConfigurationTest {
@Autowired
TimeLimiterAspect timeLimiterAspect;

@Autowired
CompositeCustomizer<TimeLimiterConfigCustomizer> compositeTimeLimiterConfigCustomizer;

@Autowired
private DummyService dummyService;

Expand All @@ -46,6 +51,8 @@ public class TimeLimiterAutoConfigurationTest {
public void testTimeLimiterAutoConfigurationTest() throws Exception {
assertThat(timeLimiterRegistry).isNotNull();
assertThat(timeLimiterProperties).isNotNull();
assertThat(compositeTimeLimiterConfigCustomizer).isNotNull();
assertThat(compositeTimeLimiterConfigCustomizer.getCustomizer("timeLimiterBackendD").isPresent()).isTrue();
assertThat(timeLimiterRegistry.getTags()).isNotEmpty();

TimeLimiterEventsEndpointResponse timeLimiterEventsBefore =
Expand Down
Loading

0 comments on commit fc8cc89

Please sign in to comment.