Skip to content

Commit bd4f290

Browse files
author
guyplusplus
committed
new property maxDurationOpenInHalfOpenState
1 parent 5b25d81 commit bd4f290

File tree

4 files changed

+42
-4
lines changed

4 files changed

+42
-4
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ It supports the 5 states:
1212
![State Machine](./state_machine.jpg)
1313

1414

15-
The following configuration properties are supported
15+
The following Resilience4j configuration properties are supported.
16+
maxDurationOpenInHalfOpenState is a new property described in the sample code paragraph.
1617

1718
| Config property | Default Value | Special Values |
1819
| ------------- | ------------- | --------|
@@ -23,6 +24,7 @@ The following configuration properties are supported
2324
| slidingWindowSize | 100 [s] | 0 to set breaker in DISABLED state, -1 to set breaker in FORCED_OPEN state |
2425
| minimumNumberOfCalls | 10 | |
2526
| waitDurationInOpenState | 60000 [ms] | |
27+
| maxDurationOpenInHalfOpenState | 120000 [ms] | If set to 0, there is no limit |
2628

2729

2830
## Sample Code
@@ -41,7 +43,9 @@ loop
4143
circuitBreaker.callFailed(doSomething duration);
4244
```
4345

44-
**Important: `callSucceeded()` or `callFailed()` must always be invoked after `isClosedForThisCall()`. Otherwise breaker in HALF-OPEN state will never move to another state.**
46+
**Important**: `callSucceeded()` or `callFailed()` must always be invoked after `isClosedForThisCall()`. Otherwise breaker in HALF-OPEN state will never move to another state, waiting for the results of the permittedNumberOfCallsInHalfOpenState calls.
47+
48+
To avoid this situation a new property maxDurationOpenInHalfOpenState is introduced. In HALF-OPEN state, after permittedNumberOfCallsInHalfOpenState calls (`isClosedForThisCall()` returns true), all its subsequent calls (`isClosedForThisCall()` returns false) won't be executed as the circuit is opened. If this situation lasts longer than maxDurationOpenInHalfOpenState ms, the breaker goes back automatically to the CLOSED state.
4549

4650
## Circuit Breaker Configuration using Properties
4751
The circuit breaker can easily be configured using `java.util.Properties`, possibly adding prefix, for example:

src/main/java/com/geckotechnology/simpleCircuitBreaker/BreakerHalfOpenState.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,36 @@ class BreakerHalfOpenState implements BreakerStateInterface {
1010
private int failureCallCount = 0;
1111
private int slowCallDurationCount = 0;
1212
private int permittedNumberOfCallsInHalfOpenStateSoFar = 0;
13+
private long lastOpenCallTimeLimit = 0;
1314

1415
BreakerHalfOpenState(CircuitBreaker circuitBreaker) {
1516
this.circuitBreaker = circuitBreaker;
1617
}
1718

1819
@Override
1920
public boolean isClosedForThisCall() {
21+
//ensure permittedNumberOfCallsInHalfOpenState calls are executed, by returning true
2022
if(permittedNumberOfCallsInHalfOpenStateSoFar < circuitBreaker.getCircuitBreakerConfig().getPermittedNumberOfCallsInHalfOpenState()) {
2123
permittedNumberOfCallsInHalfOpenStateSoFar++;
2224
return true;
2325
}
26+
//no more calls allowed
27+
//if maxDurationOpenInHalfOpenState is 0, this situation can last forever. Return false
28+
if(circuitBreaker.getCircuitBreakerConfig().getMaxDurationOpenInHalfOpenState() == 0)
29+
return false;
30+
//There is a time limit. Check if it is set. If not, it is the first call. Return false
31+
if(lastOpenCallTimeLimit == 0) {
32+
lastOpenCallTimeLimit = System.currentTimeMillis() + circuitBreaker.getCircuitBreakerConfig().getMaxDurationOpenInHalfOpenState();
33+
return false;
34+
}
35+
if(System.currentTimeMillis() >= lastOpenCallTimeLimit) {
36+
//we are beyond maxDurationOpenInHalfOpenState. Need to go back to CLOSED state
37+
logger.warning("maxDurationOpenInHalfOpenState is reached. CallCount: " + callCount + ", failureCallCount: " + failureCallCount + ", slowCallDurationCount: " + slowCallDurationCount);
38+
circuitBreaker.moveToClosedState();
39+
return circuitBreaker.isClosedForThisCall();
40+
}
41+
//situation normal, no more calls allowed
2442
return false;
25-
//@TODO add logic so that half open state is not for ever
2643
}
2744

2845
@Override

src/main/java/com/geckotechnology/simpleCircuitBreaker/CircuitBreakerConfig.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class CircuitBreakerConfig {
1414
private int slidingWindowSize = 100;
1515
private int minimumNumberOfCalls = 10;
1616
private long waitDurationOpenedState = 60000;
17+
private long maxDurationOpenInHalfOpenState = 120000;
1718

1819
/**
1920
* Default constructor with default values
@@ -53,6 +54,9 @@ public CircuitBreakerConfig(String prefix, Properties props) {
5354
value = props.getProperty(prefix + "waitDurationOpenedState");
5455
if(value != null)
5556
setWaitDurationOpenedState(Long.parseLong(value));
57+
value = props.getProperty(prefix + "maxDurationOpenInHalfOpenState");
58+
if(value != null)
59+
setMaxDurationOpenInHalfOpenState(Long.parseLong(value));
5660
}
5761

5862
public CircuitBreakerConfig clone() {
@@ -64,6 +68,7 @@ public CircuitBreakerConfig clone() {
6468
clone.failureRateThreshold = failureRateThreshold;
6569
clone.slowCallRateThreshold = slowCallRateThreshold;
6670
clone.waitDurationOpenedState = waitDurationOpenedState;
71+
clone.maxDurationOpenInHalfOpenState = maxDurationOpenInHalfOpenState;
6772
return clone;
6873
}
6974

@@ -76,6 +81,7 @@ public void logInfoConfigProperties() {
7681
logger.info("\tslidingWindowSize: " + slidingWindowSize);
7782
logger.info("\tminimumNumberOfCalls: " + minimumNumberOfCalls);
7883
logger.info("\twaitDurationOpenedState: " + waitDurationOpenedState);
84+
logger.info("\tmaxDurationOpenInHalfOpenState: " + maxDurationOpenInHalfOpenState);
7985
}
8086

8187
public int getSlidingWindowSize() {
@@ -148,4 +154,14 @@ public void setPermittedNumberOfCallsInHalfOpenState(int permittedNumberOfCallsI
148154
this.permittedNumberOfCallsInHalfOpenState = permittedNumberOfCallsInHalfOpenState;
149155
}
150156

157+
public long getMaxDurationOpenInHalfOpenState() {
158+
return maxDurationOpenInHalfOpenState;
159+
}
160+
161+
public void setMaxDurationOpenInHalfOpenState(long maxDurationOpenInHalfOpenState) {
162+
if(maxDurationOpenInHalfOpenState < 0)
163+
throw new IllegalArgumentException("maxDurationOpenInHalfOpenState must be positive or null");
164+
this.maxDurationOpenInHalfOpenState = maxDurationOpenInHalfOpenState;
165+
}
166+
151167
}

src/test/java/com/geckotechnology/simpleCircuitBreaker/breaker4.config

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ slowCallDurationThreshold=528
44
minimumNumberOfCalls=20
55
failureRateThreshold=75.1
66
slowCallRateThreshold=45
7-
waitDurationOpenedState=2000
7+
waitDurationOpenedState=2000
8+
maxDurationOpenInHalfOpenState=500

0 commit comments

Comments
 (0)