Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] master from resilience4j:master #56

Merged
merged 1 commit into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public class CircuitBreakerConfig implements Serializable {
private static final Predicate<Object> DEFAULT_RECORD_RESULT_PREDICATE = (Object object) -> false;
private static final Function<Either<Object, Throwable>, TransitionCheckResult> DEFAULT_TRANSITION_ON_RESULT
= any -> TransitionCheckResult.noTransition();
private static final Clock DEFAULT_CLOCK = Clock.systemUTC();
// The default exception predicate counts all exceptions as failures.

private transient Predicate<Throwable> recordExceptionPredicate = DEFAULT_RECORD_EXCEPTION_PREDICATE;
Expand Down Expand Up @@ -87,6 +88,7 @@ public class CircuitBreakerConfig implements Serializable {
.ofSeconds(DEFAULT_SLOW_CALL_DURATION_THRESHOLD);
private Duration maxWaitDurationInHalfOpenState = Duration
.ofSeconds(DEFAULT_WAIT_DURATION_IN_HALF_OPEN_STATE);
private transient Clock clock = DEFAULT_CLOCK;

private CircuitBreakerConfig() {
}
Expand Down Expand Up @@ -189,6 +191,10 @@ public Duration getMaxWaitDurationInHalfOpenState() {
return maxWaitDurationInHalfOpenState;
}

public Clock getClock() {
return clock;
}

public enum SlidingWindowType {
TIME_BASED, COUNT_BASED
}
Expand Down Expand Up @@ -319,6 +325,7 @@ public static class Builder {
private Duration maxWaitDurationInHalfOpenState = Duration
.ofSeconds(DEFAULT_WAIT_DURATION_IN_HALF_OPEN_STATE);
private byte createWaitIntervalFunctionCounter = 0;
private Clock clock = DEFAULT_CLOCK;


public Builder(CircuitBreakerConfig baseConfig) {
Expand All @@ -341,6 +348,7 @@ public Builder(CircuitBreakerConfig baseConfig) {
this.maxWaitDurationInHalfOpenState = baseConfig.maxWaitDurationInHalfOpenState;
this.writableStackTraceEnabled = baseConfig.writableStackTraceEnabled;
this.recordResultPredicate = baseConfig.recordResultPredicate;
this.clock = baseConfig.clock;
}

public Builder() {
Expand Down Expand Up @@ -781,6 +789,22 @@ public Builder automaticTransitionFromOpenToHalfOpenEnabled(
return this;
}

/**
* Configures a custom Clock instance to use for time measurements.
* Default value is Clock.systemUTC().
*
* @param clock the Clock to use
* @return the CircuitBreakerConfig.Builder
*/
public Builder clock(Clock clock) {
if (clock == null) {
this.clock = DEFAULT_CLOCK;
} else {
this.clock = clock;
}
return this;
}

/**
* Builds a CircuitBreakerConfig
*
Expand Down Expand Up @@ -808,6 +832,7 @@ public CircuitBreakerConfig build() {
config.currentTimestampFunction = currentTimestampFunction;
config.timestampUnit = timestampUnit;
config.recordResultPredicate = recordResultPredicate;
config.clock = clock;
return config;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,13 @@ class CircuitBreakerMetrics implements CircuitBreaker.Metrics {

private CircuitBreakerMetrics(int slidingWindowSize,
CircuitBreakerConfig.SlidingWindowType slidingWindowType,
CircuitBreakerConfig circuitBreakerConfig,
Clock clock) {
CircuitBreakerConfig circuitBreakerConfig) {
if (slidingWindowType == CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) {
this.metrics = new FixedSizeSlidingWindowMetrics(slidingWindowSize);
this.minimumNumberOfCalls = Math
.min(circuitBreakerConfig.getMinimumNumberOfCalls(), slidingWindowSize);
} else {
this.metrics = new SlidingTimeWindowMetrics(slidingWindowSize, clock);
this.metrics = new SlidingTimeWindowMetrics(slidingWindowSize, circuitBreakerConfig.getClock());
this.minimumNumberOfCalls = circuitBreakerConfig.getMinimumNumberOfCalls();
}
this.failureRateThreshold = circuitBreakerConfig.getFailureRateThreshold();
Expand All @@ -61,33 +60,33 @@ private CircuitBreakerMetrics(int slidingWindowSize,
}

private CircuitBreakerMetrics(int slidingWindowSize,
CircuitBreakerConfig circuitBreakerConfig, Clock clock) {
this(slidingWindowSize, circuitBreakerConfig.getSlidingWindowType(), circuitBreakerConfig, clock);
CircuitBreakerConfig circuitBreakerConfig) {
this(slidingWindowSize, circuitBreakerConfig.getSlidingWindowType(), circuitBreakerConfig);
}

static CircuitBreakerMetrics forClosed(CircuitBreakerConfig circuitBreakerConfig, Clock clock) {
static CircuitBreakerMetrics forClosed(CircuitBreakerConfig circuitBreakerConfig) {
return new CircuitBreakerMetrics(circuitBreakerConfig.getSlidingWindowSize(),
circuitBreakerConfig, clock);
circuitBreakerConfig);
}

static CircuitBreakerMetrics forHalfOpen(int permittedNumberOfCallsInHalfOpenState,
CircuitBreakerConfig circuitBreakerConfig, Clock clock) {
CircuitBreakerConfig circuitBreakerConfig) {
return new CircuitBreakerMetrics(permittedNumberOfCallsInHalfOpenState,
CircuitBreakerConfig.SlidingWindowType.COUNT_BASED, circuitBreakerConfig, clock);
CircuitBreakerConfig.SlidingWindowType.COUNT_BASED, circuitBreakerConfig);
}

static CircuitBreakerMetrics forForcedOpen(CircuitBreakerConfig circuitBreakerConfig, Clock clock) {
static CircuitBreakerMetrics forForcedOpen(CircuitBreakerConfig circuitBreakerConfig) {
return new CircuitBreakerMetrics(0, CircuitBreakerConfig.SlidingWindowType.COUNT_BASED,
circuitBreakerConfig, clock);
circuitBreakerConfig);
}

static CircuitBreakerMetrics forDisabled(CircuitBreakerConfig circuitBreakerConfig, Clock clock) {
static CircuitBreakerMetrics forDisabled(CircuitBreakerConfig circuitBreakerConfig) {
return new CircuitBreakerMetrics(0, CircuitBreakerConfig.SlidingWindowType.COUNT_BASED,
circuitBreakerConfig, clock);
circuitBreakerConfig);
}

static CircuitBreakerMetrics forMetricsOnly(CircuitBreakerConfig circuitBreakerConfig, Clock clock) {
return forClosed(circuitBreakerConfig, clock);
static CircuitBreakerMetrics forMetricsOnly(CircuitBreakerConfig circuitBreakerConfig) {
return forClosed(circuitBreakerConfig);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,15 @@ public final class CircuitBreakerStateMachine implements CircuitBreaker {
*
* @param name the name of the CircuitBreaker
* @param circuitBreakerConfig The CircuitBreaker configuration.
* @param clock A Clock which can be mocked in tests.
* @param schedulerFactory A SchedulerFactory which can be mocked in tests.
*/
private CircuitBreakerStateMachine(String name, CircuitBreakerConfig circuitBreakerConfig,
Clock clock, SchedulerFactory schedulerFactory, Map<String, String> tags) {
SchedulerFactory schedulerFactory, Map<String, String> tags) {
this.name = name;
this.circuitBreakerConfig = Objects
.requireNonNull(circuitBreakerConfig, "Config must not be null");
this.eventProcessor = new CircuitBreakerEventProcessor();
this.clock = clock;
this.clock = circuitBreakerConfig.getClock();
this.stateReference = new AtomicReference<>(new ClosedState());
this.schedulerFactory = schedulerFactory;
this.tags = Objects.requireNonNull(tags, "Tags must not be null");
Expand All @@ -97,29 +96,7 @@ private CircuitBreakerStateMachine(String name, CircuitBreakerConfig circuitBrea
*/
public CircuitBreakerStateMachine(String name, CircuitBreakerConfig circuitBreakerConfig,
SchedulerFactory schedulerFactory) {
this(name, circuitBreakerConfig, Clock.systemUTC(), schedulerFactory, emptyMap());
}

/**
* Creates a circuitBreaker.
*
* @param name the name of the CircuitBreaker
* @param circuitBreakerConfig The CircuitBreaker configuration.
*/
public CircuitBreakerStateMachine(String name, CircuitBreakerConfig circuitBreakerConfig,
Clock clock) {
this(name, circuitBreakerConfig, clock, SchedulerFactory.getInstance(), emptyMap());
}

/**
* Creates a circuitBreaker.
*
* @param name the name of the CircuitBreaker
* @param circuitBreakerConfig The CircuitBreaker configuration.
*/
public CircuitBreakerStateMachine(String name, CircuitBreakerConfig circuitBreakerConfig,
Clock clock, Map<String, String> tags) {
this(name, circuitBreakerConfig, clock, SchedulerFactory.getInstance(), tags);
this(name, circuitBreakerConfig, schedulerFactory, emptyMap());
}

/**
Expand All @@ -129,19 +106,18 @@ public CircuitBreakerStateMachine(String name, CircuitBreakerConfig circuitBreak
* @param circuitBreakerConfig The CircuitBreaker configuration.
*/
public CircuitBreakerStateMachine(String name, CircuitBreakerConfig circuitBreakerConfig) {
this(name, circuitBreakerConfig, Clock.systemUTC());
this(name, circuitBreakerConfig, SchedulerFactory.getInstance(), emptyMap());
}

/**
* Creates a circuitBreaker.
*
* @param name the name of the CircuitBreaker
* @param circuitBreakerConfig The CircuitBreaker configuration.
* @param tags Tags to add to the CircuitBreaker.
*/
public CircuitBreakerStateMachine(String name, CircuitBreakerConfig circuitBreakerConfig,
Map<String, String> tags) {
this(name, circuitBreakerConfig, Clock.systemUTC(), tags);
this(name, circuitBreakerConfig, SchedulerFactory.getInstance(), tags);
}

/**
Expand Down Expand Up @@ -588,7 +564,7 @@ private class ClosedState implements CircuitBreakerState {
private final AtomicBoolean isClosed;

ClosedState() {
this.circuitBreakerMetrics = CircuitBreakerMetrics.forClosed(getCircuitBreakerConfig(), clock);
this.circuitBreakerMetrics = CircuitBreakerMetrics.forClosed(getCircuitBreakerConfig());
this.isClosed = new AtomicBoolean(true);
}

Expand Down Expand Up @@ -828,7 +804,7 @@ private class DisabledState implements CircuitBreakerState {

DisabledState() {
this.circuitBreakerMetrics = CircuitBreakerMetrics
.forDisabled(getCircuitBreakerConfig(), clock);
.forDisabled(getCircuitBreakerConfig());
}

/**
Expand Down Expand Up @@ -899,7 +875,7 @@ private class MetricsOnlyState implements CircuitBreakerState {

MetricsOnlyState() {
circuitBreakerMetrics = CircuitBreakerMetrics
.forMetricsOnly(getCircuitBreakerConfig(), clock);
.forMetricsOnly(getCircuitBreakerConfig());
isFailureRateExceeded = new AtomicBoolean(false);
isSlowCallRateExceeded = new AtomicBoolean(false);
}
Expand Down Expand Up @@ -995,7 +971,7 @@ private class ForcedOpenState implements CircuitBreakerState {

ForcedOpenState(int attempts) {
this.attempts = attempts;
this.circuitBreakerMetrics = CircuitBreakerMetrics.forForcedOpen(circuitBreakerConfig, clock);
this.circuitBreakerMetrics = CircuitBreakerMetrics.forForcedOpen(circuitBreakerConfig);
}

/**
Expand Down Expand Up @@ -1074,7 +1050,7 @@ private class HalfOpenState implements CircuitBreakerState {
int permittedNumberOfCallsInHalfOpenState = circuitBreakerConfig
.getPermittedNumberOfCallsInHalfOpenState();
this.circuitBreakerMetrics = CircuitBreakerMetrics
.forHalfOpen(permittedNumberOfCallsInHalfOpenState, getCircuitBreakerConfig(), clock);
.forHalfOpen(permittedNumberOfCallsInHalfOpenState, getCircuitBreakerConfig());
this.permittedNumberOfCalls = new AtomicInteger(permittedNumberOfCallsInHalfOpenState);
this.isHalfOpen = new AtomicBoolean(true);
this.attempts = attempts;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@ public class CircuitBreakerMetricsTest {
public void testCircuitBreakerMetrics() {
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.slidingWindow(10, 10, CircuitBreakerConfig.SlidingWindowType.COUNT_BASED)
.clock(MockClock.at(2019, 1, 1, 12, 0, 0, ZoneId.of("UTC")))
.build();

CircuitBreakerMetrics circuitBreakerMetrics = CircuitBreakerMetrics
.forClosed(circuitBreakerConfig, MockClock.at(2019, 1, 1, 12, 0, 0, ZoneId.of("UTC")));
.forClosed(circuitBreakerConfig);

circuitBreakerMetrics.onSuccess(0, TimeUnit.NANOSECONDS);
circuitBreakerMetrics.onSuccess(0, TimeUnit.NANOSECONDS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public class CircuitBreakerStateMachineTest {

@Before
@SuppressWarnings("unchecked")
public void setUp() {
public void setUp() {
mockOnSuccessEventConsumer = (EventConsumer<CircuitBreakerOnSuccessEvent>) mock(EventConsumer.class);
mockOnErrorEventConsumer = (EventConsumer<CircuitBreakerOnErrorEvent>) mock(EventConsumer.class);
mockOnStateTransitionEventConsumer = (EventConsumer<CircuitBreakerOnStateTransitionEvent>) mock(EventConsumer.class);
Expand All @@ -83,7 +83,8 @@ public void setUp() {
.waitDurationInOpenState(Duration.ofSeconds(5))
.ignoreExceptions(NumberFormatException.class)
.currentTimestampFunction(clock -> clock.instant().toEpochMilli(), TimeUnit.MILLISECONDS)
.build(), mockClock);
.clock(mockClock)
.build());
}

@Test
Expand Down Expand Up @@ -427,7 +428,8 @@ public void shouldTransitionToHalfOpenAfterWaitInterval() {
.permittedNumberOfCallsInHalfOpenState(4)
.waitIntervalFunctionInOpenState(IntervalFunction.ofExponentialBackoff(5000L))
.recordException(error -> !(error instanceof NumberFormatException))
.build(), mockClock);
.clock(mockClock)
.build());

// Initially the CircuitBreaker is open
intervalCircuitBreaker.transitionToOpenState();
Expand Down
Loading