Skip to content

Commit

Permalink
Issue 773: Aded support to rate limiter configuration customization (R…
Browse files Browse the repository at this point in the history
  • Loading branch information
Romeh authored and RobWin committed Jan 9, 2020
1 parent 3592deb commit 72e5105
Show file tree
Hide file tree
Showing 30 changed files with 287 additions and 118 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.github.resilience4j.common;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* the composite of any spring resilience4j type config customizer implementations.
*/
public class CompositeCustomizer<T extends CustomizerWithName> {

private final Map<String, T> customizerMap = new HashMap<>();

public CompositeCustomizer(List<T> customizers) {
if (customizers != null && !customizers.isEmpty()) {
customizerMap.putAll(customizers.stream()
.collect(
Collectors.toMap(CustomizerWithName::name, Function.identity())));
}
}

/**
* @param instanceName the resilience4j instance name
* @return the found spring customizer if any .
*/
public Optional<T> getCustomizer(String instanceName) {
return Optional.ofNullable(customizerMap.get(instanceName));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.github.resilience4j.common;

/**
* common interface for different spring config customizers implementation
*/
public interface CustomizerWithName {

/**
* @return name of the resilience4j type instance to be customized
*/
String name();
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package io.github.resilience4j.common.circuitbreaker.configuration;

import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.common.CustomizerWithName;

/**
* Enable customization circuit breaker configuration builders programmatically.
*/
public interface CircuitBreakerConfigCustomizer {
public interface CircuitBreakerConfigCustomizer extends CustomizerWithName {

/**
* Customize circuit breaker configuration builder.
Expand All @@ -14,8 +15,4 @@ public interface CircuitBreakerConfigCustomizer {
*/
void customize(CircuitBreakerConfig.Builder configBuilder);

/**
* @return name of the circuit breaker instance to be customized
*/
String name();
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig.Builder;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig.SlidingWindowType;
import io.github.resilience4j.common.CommonProperties;
import io.github.resilience4j.common.CompositeCustomizer;
import io.github.resilience4j.common.utils.ConfigUtils;
import io.github.resilience4j.core.ClassUtils;
import io.github.resilience4j.core.ConfigurationNotFoundException;
Expand Down Expand Up @@ -52,7 +53,7 @@ public Optional<InstanceProperties> findCircuitBreakerProperties(String name) {

public CircuitBreakerConfig createCircuitBreakerConfig(String backendName,
InstanceProperties instanceProperties,
CompositeCircuitBreakerCustomizer compositeCircuitBreakerCustomizer) {
CompositeCustomizer<CircuitBreakerConfigCustomizer> compositeCircuitBreakerCustomizer) {
if (StringUtils.isNotEmpty(instanceProperties.getBaseConfig())) {
InstanceProperties baseProperties = configs.get(instanceProperties.getBaseConfig());
if (baseProperties == null) {
Expand All @@ -68,16 +69,20 @@ public CircuitBreakerConfig createCircuitBreakerConfig(String backendName,

private CircuitBreakerConfig buildConfigFromBaseConfig(InstanceProperties instanceProperties,
InstanceProperties baseProperties,
CompositeCircuitBreakerCustomizer customizerMap, String backendName) {
CompositeCustomizer<CircuitBreakerConfigCustomizer> compositeCircuitBreakerCustomizer,
String backendName) {
ConfigUtils.mergePropertiesIfAny(instanceProperties, baseProperties);
CircuitBreakerConfig baseConfig = buildConfig(custom(), baseProperties, customizerMap,
CircuitBreakerConfig baseConfig = buildConfig(custom(), baseProperties,
compositeCircuitBreakerCustomizer,
backendName);
return buildConfig(from(baseConfig), instanceProperties, compositeCircuitBreakerCustomizer,
backendName);
return buildConfig(from(baseConfig), instanceProperties, customizerMap, backendName);
}

@SuppressWarnings("deprecation") // deprecated API use left for backward compatibility
private CircuitBreakerConfig buildConfig(Builder builder, InstanceProperties properties,
CompositeCircuitBreakerCustomizer compositeCircuitBreakerCustomizer, String backendName) {
CompositeCustomizer<CircuitBreakerConfigCustomizer> compositeCircuitBreakerCustomizer,
String backendName) {
if (properties == null) {
return builder.build();
}
Expand Down Expand Up @@ -147,7 +152,7 @@ private CircuitBreakerConfig buildConfig(Builder builder, InstanceProperties pro
builder.automaticTransitionFromOpenToHalfOpenEnabled(
properties.automaticTransitionFromOpenToHalfOpenEnabled);
}
compositeCircuitBreakerCustomizer.getCircuitBreakerConfigCustomizer(backendName).ifPresent(
compositeCircuitBreakerCustomizer.getCustomizer(backendName).ifPresent(
circuitBreakerConfigCustomizer -> circuitBreakerConfigCustomizer.customize(builder));
return builder.build();
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.github.resilience4j.common.ratelimiter.configuration;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* the composite of any rate limiter {@link RateLimiterConfigCustomizer} implementations.
*/
public class CompositeRateLimiterCustomizer {

private final Map<String, RateLimiterConfigCustomizer> customizerMap = new HashMap<>();

public CompositeRateLimiterCustomizer(List<RateLimiterConfigCustomizer> customizers) {
if (customizers != null && !customizers.isEmpty()) {
customizerMap.putAll(customizers.stream()
.collect(
Collectors.toMap(RateLimiterConfigCustomizer::name, Function.identity())));
}
}

/**
* @param rateLimiterInstanceName the rate limiter instance name
* @return the found {@link RateLimiterConfigCustomizer} if any .
*/
public Optional<RateLimiterConfigCustomizer> getRateLimiterConfigCustomizer(
String rateLimiterInstanceName) {
return Optional.ofNullable(customizerMap.get(rateLimiterInstanceName));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.github.resilience4j.common.ratelimiter.configuration;

import io.github.resilience4j.common.CustomizerWithName;
import io.github.resilience4j.ratelimiter.RateLimiterConfig;

/**
* Enable customization rate limiter configuration builders programmatically.
*/
public interface RateLimiterConfigCustomizer extends CustomizerWithName {

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

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import java.util.Objects;
import java.util.Optional;

public class RateLimiterConfigurationProperties extends CommonProperties{
public class RateLimiterConfigurationProperties extends CommonProperties {

private Map<String, InstanceProperties> instances = new HashMap<>();
private Map<String, InstanceProperties> configs = new HashMap<>();
Expand All @@ -42,7 +42,8 @@ public Optional<InstanceProperties> findRateLimiterProperties(String name) {
}

public RateLimiterConfig createRateLimiterConfig(
@Nullable InstanceProperties instanceProperties) {
@Nullable InstanceProperties instanceProperties,
CompositeRateLimiterCustomizer compositeRateLimiterCustomizer, String instanceName) {
if (instanceProperties == null) {
return RateLimiterConfig.ofDefaults();
}
Expand All @@ -51,21 +52,26 @@ public RateLimiterConfig createRateLimiterConfig(
if (baseProperties == null) {
throw new ConfigurationNotFoundException(instanceProperties.getBaseConfig());
}
return buildConfigFromBaseConfig(baseProperties, instanceProperties);
return buildConfigFromBaseConfig(baseProperties, instanceProperties,
compositeRateLimiterCustomizer, instanceName);
}
return buildRateLimiterConfig(RateLimiterConfig.custom(), instanceProperties);
return buildRateLimiterConfig(RateLimiterConfig.custom(), instanceProperties,
compositeRateLimiterCustomizer, instanceName);
}

private RateLimiterConfig buildConfigFromBaseConfig(InstanceProperties baseProperties,
InstanceProperties instanceProperties) {
InstanceProperties instanceProperties,
CompositeRateLimiterCustomizer compositeRateLimiterCustomizer, String instanceName) {
ConfigUtils.mergePropertiesIfAny(baseProperties, instanceProperties);
RateLimiterConfig baseConfig = buildRateLimiterConfig(RateLimiterConfig.custom(),
baseProperties);
return buildRateLimiterConfig(RateLimiterConfig.from(baseConfig), instanceProperties);
baseProperties, compositeRateLimiterCustomizer, instanceName);
return buildRateLimiterConfig(RateLimiterConfig.from(baseConfig), instanceProperties,
compositeRateLimiterCustomizer, instanceName);
}

private RateLimiterConfig buildRateLimiterConfig(RateLimiterConfig.Builder builder,
@Nullable InstanceProperties instanceProperties) {
@Nullable InstanceProperties instanceProperties,
CompositeRateLimiterCustomizer compositeRateLimiterCustomizer, String instanceName) {
if (instanceProperties == null) {
return builder.build();
}
Expand All @@ -85,16 +91,19 @@ private RateLimiterConfig buildRateLimiterConfig(RateLimiterConfig.Builder build
if (instanceProperties.getWritableStackTraceEnabled() != null) {
builder.writableStackTraceEnabled(instanceProperties.getWritableStackTraceEnabled());
}

compositeRateLimiterCustomizer.getRateLimiterConfigCustomizer(instanceName).ifPresent(
rateLimiterConfigCustomizer -> rateLimiterConfigCustomizer.customize(builder));
return builder.build();
}

private InstanceProperties getLimiterProperties(String limiter) {
return instances.get(limiter);
}

public RateLimiterConfig createRateLimiterConfig(String limiter) {
return createRateLimiterConfig(getLimiterProperties(limiter));
public RateLimiterConfig createRateLimiterConfig(String limiter,
CompositeRateLimiterCustomizer compositeRateLimiterCustomizer) {
return createRateLimiterConfig(getLimiterProperties(limiter),
compositeRateLimiterCustomizer, limiter);
}

@Nullable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
package io.github.resilience4j.common.retry.configuration;

import io.github.resilience4j.common.CustomizerWithName;
import io.github.resilience4j.retry.RetryConfig;

/**
* Enable customization retry configuration builders programmatically.
*/
public interface RetryConfigCustomizer {
public interface RetryConfigCustomizer extends CustomizerWithName {

/**
* Retry configuration builder.
*
* @param configBuilder to be customized
*/
void customize(RetryConfig.Builder configBuilder);

/**
* @return name of the retry instance to be customized
*/
String name();
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package io.github.resilience4j.common.circuitbreaker.configuration;

import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.common.CompositeCustomizer;
import io.github.resilience4j.common.RecordFailurePredicate;
import io.github.resilience4j.core.ConfigurationNotFoundException;
import org.junit.Test;
Expand Down Expand Up @@ -286,7 +287,7 @@ public void testIllegalArgumentOnSlowCallDurationThreshold() {
defaultProperties.setSlowCallDurationThreshold(Duration.ZERO);
}

private CompositeCircuitBreakerCustomizer compositeCircuitBreakerCustomizer() {
return new CompositeCircuitBreakerCustomizer(Collections.emptyList());
private CompositeCustomizer<CircuitBreakerConfigCustomizer> compositeCircuitBreakerCustomizer() {
return new CompositeCustomizer<>(Collections.emptyList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.junit.Test;

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

Expand Down Expand Up @@ -58,13 +59,13 @@ public void testRateLimiterRegistry() {
assertThat(rateLimiterConfigurationProperties.getInstances().size()).isEqualTo(2);
assertThat(rateLimiterConfigurationProperties.getLimiters().size()).isEqualTo(2);
RateLimiterConfig rateLimiter = rateLimiterConfigurationProperties
.createRateLimiterConfig("backend1");
.createRateLimiterConfig("backend1", compositeRateLimiterCustomizer());
assertThat(rateLimiter).isNotNull();
assertThat(rateLimiter.getLimitForPeriod()).isEqualTo(2);
assertThat(rateLimiter.isWritableStackTraceEnabled()).isFalse();

RateLimiterConfig rateLimiter2 = rateLimiterConfigurationProperties
.createRateLimiterConfig("backend2");
.createRateLimiterConfig("backend2", compositeRateLimiterCustomizer());
assertThat(rateLimiter2).isNotNull();
assertThat(rateLimiter2.getLimitForPeriod()).isEqualTo(4);
assertThat(rateLimiter2.isWritableStackTraceEnabled()).isTrue();
Expand Down Expand Up @@ -112,23 +113,23 @@ public void testCreateRateLimiterRegistryWithSharedConfigs() {

// Should get default config and override LimitForPeriod
RateLimiterConfig rateLimiter1 = rateLimiterConfigurationProperties
.createRateLimiterConfig("backendWithDefaultConfig");
.createRateLimiterConfig("backendWithDefaultConfig", compositeRateLimiterCustomizer());
assertThat(rateLimiter1).isNotNull();
assertThat(rateLimiter1.getLimitForPeriod()).isEqualTo(200);
assertThat(rateLimiter1.getLimitRefreshPeriod()).isEqualTo(Duration.ofMillis(5));
assertThat(rateLimiter1.isWritableStackTraceEnabled()).isTrue();

// Should get shared config and override LimitForPeriod
RateLimiterConfig rateLimiter2 = rateLimiterConfigurationProperties
.createRateLimiterConfig("backendWithSharedConfig");
.createRateLimiterConfig("backendWithSharedConfig", compositeRateLimiterCustomizer());
assertThat(rateLimiter2).isNotNull();
assertThat(rateLimiter2.getLimitForPeriod()).isEqualTo(300);
assertThat(rateLimiter2.getLimitRefreshPeriod()).isEqualTo(Duration.ofMillis(6));
assertThat(rateLimiter2.isWritableStackTraceEnabled()).isTrue();

// Unknown backend should get default config of Registry
RateLimiterConfig rerateLimiter3 = rateLimiterConfigurationProperties
.createRateLimiterConfig("unknownBackend");
.createRateLimiterConfig("unknownBackend", compositeRateLimiterCustomizer());
assertThat(rerateLimiter3).isNotNull();
assertThat(rerateLimiter3.getLimitForPeriod()).isEqualTo(50);
assertThat(rerateLimiter3.isWritableStackTraceEnabled()).isTrue();
Expand All @@ -146,7 +147,8 @@ public void testCreateRateLimiterRegistryWithUnknownConfig() {

//When
assertThatThrownBy(
() -> rateLimiterConfigurationProperties.createRateLimiterConfig("backend"))
() -> rateLimiterConfigurationProperties
.createRateLimiterConfig("backend", compositeRateLimiterCustomizer()))
.isInstanceOf(ConfigurationNotFoundException.class)
.hasMessage("Configuration with name 'unknownConfig' does not exist");
}
Expand Down Expand Up @@ -176,4 +178,8 @@ public void testIllegalArgumentOnEventConsumerBufferSize() {
defaultProperties.setEventConsumerBufferSize(-1);
}

private CompositeRateLimiterCustomizer compositeRateLimiterCustomizer() {
return new CompositeRateLimiterCustomizer(Collections.emptyList());
}

}
Loading

0 comments on commit 72e5105

Please sign in to comment.