Skip to content

Commit

Permalink
Issue ReactiveX#268 and ReactiveX#291: Allow sharing of CircuitBreake…
Browse files Browse the repository at this point in the history
…r configurations and overriding of Spring beans.
  • Loading branch information
Romeh authored and RobWin committed Apr 24, 2019
1 parent ab0d8a0 commit 61cf042
Show file tree
Hide file tree
Showing 100 changed files with 4,048 additions and 746 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@
build
classes
*/out
.classpath
.project
.settings
*/bin
*.orig
9 changes: 3 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,10 @@ sonarqube {
properties {
property "sonar.projectName", "resilience4j"
property "sonar.projectKey", "resilience4j_resilience4j"

property "sonar.links.homepage","https://github.com/resilience4j/resilience4j"
property "sonar.links.ci","https://travis-ci.org/resilience4j/resilience4j"
property "sonar.links.scm","https://github.com/resilience4j/resilience4j"
property "sonar.links.issue","https://github.com/resilience4j/resilience4j/issues"

// property "sonar.jacoco.reportPaths","build/reports/jacoco/test"

property "sonar.language","java"
}
}
Expand All @@ -108,8 +104,9 @@ subprojects {
}
}
afterEvaluate {
// exclude subprojects that don't produce a jar file.
if(!project.name.equals('resilience4j-bom') && !project.name.equals('resilience4j-documentation') && !project.name.equals('resilience4j-test')) {
// exclude subprojects that don't produce a jar file or by design.
if(!project.name.equals('resilience4j-bom') && !project.name.equals('resilience4j-documentation')
&& !project.name.equals('resilience4j-test') && !project.name.equals('resilience4j-spring-boot-common')) {
jar {
inputs.property('moduleName', moduleName)
manifest.attributes(
Expand Down
3 changes: 2 additions & 1 deletion libraries.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ ext {

// Aspectj for Spring addon
aspectj: "org.aspectj:aspectjrt:${aspectjVersion}",

// spring test
spring_test: "org.springframework:spring-test:${springVersion}",
// Spring Boot addon
spring_core: "org.springframework:spring-core:${springVersion}",
spring_context: "org.springframework:spring-context:${springVersion}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@
*/
package io.github.resilience4j.circuitbreaker;

import io.github.resilience4j.core.lang.Nullable;

import java.time.Duration;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.Predicate;

import io.github.resilience4j.core.lang.Nullable;


/**
* A {@link CircuitBreakerConfig} configures a {@link CircuitBreaker}
Expand All @@ -44,8 +44,27 @@ public class CircuitBreakerConfig {
// The default exception predicate counts all exceptions as failures.
private Predicate<Throwable> recordFailurePredicate = DEFAULT_RECORD_FAILURE_PREDICATE;
private boolean automaticTransitionFromOpenToHalfOpenEnabled = false;
private String configurationName;

private CircuitBreakerConfig(){
private CircuitBreakerConfig() {
}

/**
* Returns a builder to create a custom CircuitBreakerConfig.
*
* @return a {@link Builder}
*/
public static Builder custom() {
return new Builder();
}

/**
* Creates a default CircuitBreaker configuration.
*
* @return a default CircuitBreaker configuration.
*/
public static CircuitBreakerConfig ofDefaults() {
return new Builder().build();
}

public float getFailureRateThreshold() {
Expand All @@ -72,27 +91,16 @@ public boolean isAutomaticTransitionFromOpenToHalfOpenEnabled() {
return automaticTransitionFromOpenToHalfOpenEnabled;
}

/**
* Returns a builder to create a custom CircuitBreakerConfig.
*
* @return a {@link Builder}
*/
public static Builder custom(){
return new Builder();
}

/**
* Creates a default CircuitBreaker configuration.
*
* @return a default CircuitBreaker configuration.
*/
public static CircuitBreakerConfig ofDefaults(){
return new Builder().build();
@Nullable
public String getConfigurationName() {
return configurationName;
}

public static class Builder {
@Nullable private Predicate<Throwable> recordFailurePredicate;
@Nullable private Predicate<Throwable> errorRecordingPredicate;
@Nullable
private Predicate<Throwable> recordFailurePredicate;
@Nullable
private Predicate<Throwable> errorRecordingPredicate;
@SuppressWarnings("unchecked")
private Class<? extends Throwable>[] recordExceptions = new Class[0];
@SuppressWarnings("unchecked")
Expand All @@ -102,10 +110,17 @@ public static class Builder {
private int ringBufferSizeInClosedState = DEFAULT_RING_BUFFER_SIZE_IN_CLOSED_STATE;
private Duration waitDurationInOpenState = Duration.ofSeconds(DEFAULT_WAIT_DURATION_IN_OPEN_STATE);
private boolean automaticTransitionFromOpenToHalfOpenEnabled = false;
@Nullable
private String configurationName;

static Predicate<Throwable> makePredicate(Class<? extends Throwable> exClass) {

return (Throwable e) -> exClass.isAssignableFrom(e.getClass());
}

/**
* Configures the failure rate threshold in percentage above which the CircuitBreaker should trip open and start short-circuiting calls.
*
* <p>
* The threshold must be greater than 0 and not greater than 100. Default value is 50 percentage.
*
* @param failureRateThreshold the failure rate threshold in percentage
Expand Down Expand Up @@ -138,14 +153,14 @@ public Builder waitDurationInOpenState(Duration waitDurationInOpenState) {
* Configures the size of the ring buffer when the CircuitBreaker is half open. The CircuitBreaker stores the success/failure success / failure status of the latest calls in a ring buffer.
* For example, if {@code ringBufferSizeInClosedState} is 10, then at least 10 calls must be evaluated, before the failure rate can be calculated.
* If only 9 calls have been evaluated the CircuitBreaker will not trip back to closed or open even if all 9 calls have failed.
*
* <p>
* The size must be greater than 0. Default size is 10.
*
* @param ringBufferSizeInHalfOpenState the size of the ring buffer when the CircuitBreaker is is half open
* @return the CircuitBreakerConfig.Builder
*/
public Builder ringBufferSizeInHalfOpenState(int ringBufferSizeInHalfOpenState) {
if (ringBufferSizeInHalfOpenState < 1 ) {
if (ringBufferSizeInHalfOpenState < 1) {
throw new IllegalArgumentException("ringBufferSizeInHalfOpenState must be greater than 0");
}
this.ringBufferSizeInHalfOpenState = ringBufferSizeInHalfOpenState;
Expand All @@ -156,7 +171,7 @@ public Builder ringBufferSizeInHalfOpenState(int ringBufferSizeInHalfOpenState)
* Configures the size of the ring buffer when the CircuitBreaker is closed. The CircuitBreaker stores the success/failure success / failure status of the latest calls in a ring buffer.
* For example, if {@code ringBufferSizeInClosedState} is 100, then at least 100 calls must be evaluated, before the failure rate can be calculated.
* If only 99 calls have been evaluated the CircuitBreaker will not trip open even if all 99 calls have failed.
*
* <p>
* The size must be greater than 0. Default size is 100.
*
* @param ringBufferSizeInClosedState the size of the ring buffer when the CircuitBreaker is closed.
Expand Down Expand Up @@ -185,18 +200,19 @@ public Builder recordFailure(Predicate<Throwable> predicate) {
/**
* Configures a list of error classes that are recorded as a failure and thus increase the failure rate.
* Any exception matching or inheriting from one of the list should count as a failure, unless ignored via
* @see #ignoreExceptions(Class[]) ). Ignoring an exception has priority over recording an exception.
*
* Example:
* recordExceptions(Throwable.class) and ignoreExceptions(RuntimeException.class)
* would capture all Errors and checked Exceptions, and ignore unchecked
*
* For a more sophisticated exception management use the
* @see #recordFailure(Predicate) method
*
* @param errorClasses the error classes that are recorded
* @return the CircuitBreakerConfig.Builder
* @see #ignoreExceptions(Class[]) ). Ignoring an exception has priority over recording an exception.
* <p>
* Example:
* recordExceptions(Throwable.class) and ignoreExceptions(RuntimeException.class)
* would capture all Errors and checked Exceptions, and ignore unchecked
* <p>
* For a more sophisticated exception management use the
* @see #recordFailure(Predicate) method
*/
@SuppressWarnings("unchecked")
@SafeVarargs
public final Builder recordExceptions(Class<? extends Throwable>... errorClasses) {
this.recordExceptions = errorClasses != null ? errorClasses : new Class[0];
Expand All @@ -206,22 +222,23 @@ public final Builder recordExceptions(Class<? extends Throwable>... errorClasses
/**
* Configures a list of error classes that are ignored as a failure and thus do not increase the failure rate.
* Any exception matching or inheriting from one of the list will not count as a failure, even if marked via
* @see #recordExceptions(Class[]) . Ignoring an exception has priority over recording an exception.
*
* Example:
* ignoreExceptions(Throwable.class) and recordExceptions(Exception.class)
* would capture nothing
*
* Example:
* ignoreExceptions(Exception.class) and recordExceptions(Throwable.class)
* would capture Errors
*
* For a more sophisticated exception management use the
* @see #recordFailure(Predicate) method
*
* @param errorClasses the error classes that are recorded
* @return the CircuitBreakerConfig.Builder
* @see #recordExceptions(Class[]) . Ignoring an exception has priority over recording an exception.
* <p>
* Example:
* ignoreExceptions(Throwable.class) and recordExceptions(Exception.class)
* would capture nothing
* <p>
* Example:
* ignoreExceptions(Exception.class) and recordExceptions(Throwable.class)
* would capture Errors
* <p>
* For a more sophisticated exception management use the
* @see #recordFailure(Predicate) method
*/
@SuppressWarnings("unchecked")
@SafeVarargs
public final Builder ignoreExceptions(Class<? extends Throwable>... errorClasses) {
this.ignoreExceptions = errorClasses != null ? errorClasses : new Class[0];
Expand All @@ -238,6 +255,17 @@ public Builder enableAutomaticTransitionFromOpenToHalfOpen() {
return this;
}

/**
* A name for referencing the configuration. This is not required, but can be used for referencing configurations if set.
*
* @param configurationName A name for referencing the configuration.
* @return The CircuitBreakerConfig.Builder
*/
public Builder configurationName(String configurationName) {
this.configurationName = configurationName;
return this;
}

/**
* Builds a CircuitBreakerConfig
*
Expand All @@ -250,10 +278,11 @@ public CircuitBreakerConfig build() {
config.failureRateThreshold = failureRateThreshold;
config.ringBufferSizeInClosedState = ringBufferSizeInClosedState;
config.ringBufferSizeInHalfOpenState = ringBufferSizeInHalfOpenState;
if(errorRecordingPredicate != null) {
if (errorRecordingPredicate != null) {
config.recordFailurePredicate = errorRecordingPredicate;
}
config.automaticTransitionFromOpenToHalfOpenEnabled = automaticTransitionFromOpenToHalfOpenEnabled;
config.configurationName = configurationName;
return config;
}

Expand Down Expand Up @@ -284,10 +313,5 @@ private Optional<Predicate<Throwable>> buildIgnoreExceptionsPredicate() {
.reduce(Predicate::or)
.map(Predicate::negate);
}

static Predicate<Throwable> makePredicate(Class<? extends Throwable> exClass) {

return (Throwable e) -> exClass.isAssignableFrom(e.getClass());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,65 +19,66 @@
package io.github.resilience4j.circuitbreaker;


import java.util.function.Supplier;

import io.github.resilience4j.circuitbreaker.internal.InMemoryCircuitBreakerRegistry;
import io.github.resilience4j.core.Registry;
import io.vavr.collection.Seq;

import java.util.function.Supplier;

/**
* The {@link CircuitBreakerRegistry} is a factory to create CircuitBreaker instances which stores all CircuitBreaker instances in a registry.
*/
public interface CircuitBreakerRegistry {
public interface CircuitBreakerRegistry extends Registry<CircuitBreaker, CircuitBreakerConfig> {
/**
* Returns all managed {@link CircuitBreaker} instances.
*
* @return all managed {@link CircuitBreaker} instances.
*/
Seq<CircuitBreaker> getAllCircuitBreakers();

/**
* Returns all managed {@link CircuitBreaker} instances.
*
* @return all managed {@link CircuitBreaker} instances.
*/
Seq<CircuitBreaker> getAllCircuitBreakers();
/**
* Returns a managed {@link CircuitBreaker} or creates a new one with the default CircuitBreaker configuration.
*
* @param name the name of the CircuitBreaker
* @return The {@link CircuitBreaker}
*/
CircuitBreaker circuitBreaker(String name);

/**
* Returns a managed {@link CircuitBreaker} or creates a new one with the default CircuitBreaker configuration.
*
* @param name the name of the CircuitBreaker
* @return The {@link CircuitBreaker}
*/
CircuitBreaker circuitBreaker(String name);
/**
* Returns a managed {@link CircuitBreaker} or creates a new one with a custom CircuitBreaker configuration.
*
* @param name the name of the CircuitBreaker
* @param circuitBreakerConfig a custom CircuitBreaker configuration
* @return The {@link CircuitBreaker}
*/
CircuitBreaker circuitBreaker(String name, CircuitBreakerConfig circuitBreakerConfig);

/**
* Returns a managed {@link CircuitBreaker} or creates a new one with a custom CircuitBreaker configuration.
*
* @param name the name of the CircuitBreaker
* @param circuitBreakerConfig a custom CircuitBreaker configuration
* @return The {@link CircuitBreaker}
*/
CircuitBreaker circuitBreaker(String name, CircuitBreakerConfig circuitBreakerConfig);
/**
* Returns a managed {@link CircuitBreaker} or creates a new one with a custom CircuitBreaker configuration.
*
* @param name the name of the CircuitBreaker
* @param circuitBreakerConfigSupplier a supplier of a custom CircuitBreaker configuration
* @return The {@link CircuitBreaker}
*/
CircuitBreaker circuitBreaker(String name, Supplier<CircuitBreakerConfig> circuitBreakerConfigSupplier);

/**
* Returns a managed {@link CircuitBreaker} or creates a new one with a custom CircuitBreaker configuration.
*
* @param name the name of the CircuitBreaker
* @param circuitBreakerConfigSupplier a supplier of a custom CircuitBreaker configuration
* @return The {@link CircuitBreaker}
*/
CircuitBreaker circuitBreaker(String name, Supplier<CircuitBreakerConfig> circuitBreakerConfigSupplier);
/**
* Creates a CircuitBreakerRegistry with a custom CircuitBreaker configuration.
*
* @param circuitBreakerConfig a custom CircuitBreaker configuration
* @return a CircuitBreakerRegistry with a custom CircuitBreaker configuration.
*/
static CircuitBreakerRegistry of(CircuitBreakerConfig circuitBreakerConfig) {
return new InMemoryCircuitBreakerRegistry(circuitBreakerConfig);
}

/**
* Creates a CircuitBreakerRegistry with a custom CircuitBreaker configuration.
*
* @param circuitBreakerConfig a custom CircuitBreaker configuration
* @return a CircuitBreakerRegistry with a custom CircuitBreaker configuration.
*/
static CircuitBreakerRegistry of(CircuitBreakerConfig circuitBreakerConfig){
return new InMemoryCircuitBreakerRegistry(circuitBreakerConfig);
}
/**
* Creates a CircuitBreakerRegistry with a default CircuitBreaker configuration.
*
* @return a CircuitBreakerRegistry with a default CircuitBreaker configuration.
*/
static CircuitBreakerRegistry ofDefaults() {
return new InMemoryCircuitBreakerRegistry();
}

/**
* Creates a CircuitBreakerRegistry with a default CircuitBreaker configuration.
*
* @return a CircuitBreakerRegistry with a default CircuitBreaker configuration.
*/
static CircuitBreakerRegistry ofDefaults(){
return new InMemoryCircuitBreakerRegistry();
}
}
Loading

0 comments on commit 61cf042

Please sign in to comment.