public class EventCountCircuitBreaker extends AbstractCircuitBreaker<java.lang.Integer>
A simple implementation of the Circuit Breaker pattern that counts specific events.
A circuit breaker can be used to protect an application against unreliable
services or unexpected load. A newly created EventCountCircuitBreaker
object is
initially in state closed meaning that no problem has been detected. When the
application encounters specific events (like errors or service timeouts), it tells the
circuit breaker to increment an internal counter. If the number of events reported in a
specific time interval exceeds a configurable threshold, the circuit breaker changes
into state open. This means that there is a problem with the associated sub
system; the application should no longer call it, but give it some time to settle down.
The circuit breaker can be configured to switch back to closed state after a
certain time frame if the number of events received goes below a threshold.
When a EventCountCircuitBreaker
object is constructed the following parameters
can be provided:
This class supports the following typical use cases:
Protecting against load peaks
Imagine you have a server which can handle a certain number of requests per minute.
Suddenly, the number of requests increases significantly - maybe because a connected
partner system is going mad or due to a denial of service attack. A
EventCountCircuitBreaker
can be configured to stop the application from
processing requests when a sudden peak load is detected and to start request processing
again when things calm down. The following code fragment shows a typical example of
such a scenario. Here the EventCountCircuitBreaker
allows up to 1000 requests
per minute before it interferes. When the load goes down again to 800 requests per
second it switches back to state closed:
EventCountCircuitBreaker breaker = new EventCountCircuitBreaker(1000, 1, TimeUnit.MINUTE, 800); ... public void handleRequest(Request request) { if (breaker.incrementAndCheckState()) { // actually handle this request } else { // do something else, e.g. send an error code } }
Deal with an unreliable service
In this scenario, an application uses an external service which may fail from time to time. If there are too many errors, the service is considered down and should not be called for a while. This can be achieved using the following pattern - in this concrete example we accept up to 5 errors in 2 minutes; if this limit is reached, the service is given a rest time of 10 minutes:
EventCountCircuitBreaker breaker = new EventCountCircuitBreaker(5, 2, TimeUnit.MINUTE, 5, 10, TimeUnit.MINUTE); ... public void handleRequest(Request request) { if (breaker.checkState()) { try { service.doSomething(); } catch (ServiceException ex) { breaker.incrementAndCheckState(); } } else { // return an error code, use an alternative service, etc. } }
In addition to automatic state transitions, the state of a circuit breaker can be
changed manually using the methods open()
and close()
. It is also
possible to register PropertyChangeListener
objects that get notified whenever
a state transition occurs. This is useful, for instance to directly react on a freshly
detected error condition.
Implementation notes:
Modifier and Type | Class and Description |
---|---|
private static class |
EventCountCircuitBreaker.CheckIntervalData
An internally used data class holding information about the checks performed by
this class.
|
private static class |
EventCountCircuitBreaker.StateStrategy
Internally used class for executing check logic based on the current state of the
circuit breaker.
|
private static class |
EventCountCircuitBreaker.StateStrategyClosed
A specialized
StateStrategy implementation for the state closed. |
private static class |
EventCountCircuitBreaker.StateStrategyOpen
A specialized
StateStrategy implementation for the state open. |
AbstractCircuitBreaker.State
Modifier and Type | Field and Description |
---|---|
private java.util.concurrent.atomic.AtomicReference<EventCountCircuitBreaker.CheckIntervalData> |
checkIntervalData
Stores information about the current check interval.
|
private long |
closingInterval
The time interval for closing the circuit breaker.
|
private int |
closingThreshold
The threshold for closing the circuit breaker.
|
private long |
openingInterval
The time interval for opening the circuit breaker.
|
private int |
openingThreshold
The threshold for opening the circuit breaker.
|
private static java.util.Map<AbstractCircuitBreaker.State,EventCountCircuitBreaker.StateStrategy> |
STRATEGY_MAP
A map for accessing the strategy objects for the different states.
|
PROPERTY_NAME, state
Constructor and Description |
---|
EventCountCircuitBreaker(int threshold,
long checkInterval,
java.util.concurrent.TimeUnit checkUnit)
Creates a new instance of
EventCountCircuitBreaker which uses the same parameters for
opening and closing checks. |
EventCountCircuitBreaker(int openingThreshold,
long checkInterval,
java.util.concurrent.TimeUnit checkUnit,
int closingThreshold)
Creates a new instance of
EventCountCircuitBreaker with the same interval for opening
and closing checks. |
EventCountCircuitBreaker(int openingThreshold,
long openingInterval,
java.util.concurrent.TimeUnit openingUnit,
int closingThreshold,
long closingInterval,
java.util.concurrent.TimeUnit closingUnit)
Creates a new instance of
EventCountCircuitBreaker and initializes all properties for
opening and closing it based on threshold values for events occurring in specific
intervals. |
Modifier and Type | Method and Description |
---|---|
private void |
changeStateAndStartNewCheckInterval(AbstractCircuitBreaker.State newState)
Changes the state of this circuit breaker and also initializes a new
CheckIntervalData object. |
boolean |
checkState()
Checks the state of this circuit breaker and changes it if necessary.
|
void |
close()
Closes this circuit breaker.
|
private static java.util.Map<AbstractCircuitBreaker.State,EventCountCircuitBreaker.StateStrategy> |
createStrategyMap()
Creates the map with strategy objects.
|
long |
getClosingInterval()
Returns the interval (in nanoseconds) for checking for the closing threshold.
|
int |
getClosingThreshold()
Returns the threshold value for closing the circuit breaker.
|
long |
getOpeningInterval()
Returns the interval (in nanoseconds) for checking for the opening threshold.
|
int |
getOpeningThreshold()
Returns the threshold value for opening the circuit breaker.
|
boolean |
incrementAndCheckState()
Increments the monitored value by 1 and performs a check of the current state of this
circuit breaker.
|
boolean |
incrementAndCheckState(java.lang.Integer increment)
Increments the monitored value and performs a check of the current state of this
circuit breaker.
|
private EventCountCircuitBreaker.CheckIntervalData |
nextCheckIntervalData(int increment,
EventCountCircuitBreaker.CheckIntervalData currentData,
AbstractCircuitBreaker.State currentState,
long time)
Calculates the next
CheckIntervalData object based on the current data and
the current state. |
(package private) long |
now()
Returns the current time in nanoseconds.
|
void |
open()
Opens this circuit breaker.
|
private boolean |
performStateCheck(int increment)
Actually checks the state of this circuit breaker and executes a state transition
if necessary.
|
private static EventCountCircuitBreaker.StateStrategy |
stateStrategy(AbstractCircuitBreaker.State state)
Returns the
StateStrategy object responsible for the given state. |
private boolean |
updateCheckIntervalData(EventCountCircuitBreaker.CheckIntervalData currentData,
EventCountCircuitBreaker.CheckIntervalData nextData)
Updates the
CheckIntervalData object. |
addChangeListener, changeState, isClosed, isOpen, isOpen, removeChangeListener
private static final java.util.Map<AbstractCircuitBreaker.State,EventCountCircuitBreaker.StateStrategy> STRATEGY_MAP
private final java.util.concurrent.atomic.AtomicReference<EventCountCircuitBreaker.CheckIntervalData> checkIntervalData
private final int openingThreshold
private final long openingInterval
private final int closingThreshold
private final long closingInterval
public EventCountCircuitBreaker(int openingThreshold, long openingInterval, java.util.concurrent.TimeUnit openingUnit, int closingThreshold, long closingInterval, java.util.concurrent.TimeUnit closingUnit)
EventCountCircuitBreaker
and initializes all properties for
opening and closing it based on threshold values for events occurring in specific
intervals.openingThreshold
- the threshold for opening the circuit breaker; if this
number of events is received in the time span determined by the opening interval,
the circuit breaker is openedopeningInterval
- the interval for opening the circuit breakeropeningUnit
- the TimeUnit
defining the opening intervalclosingThreshold
- the threshold for closing the circuit breaker; if the
number of events received in the time span determined by the closing interval goes
below this threshold, the circuit breaker is closed againclosingInterval
- the interval for closing the circuit breakerclosingUnit
- the TimeUnit
defining the closing intervalpublic EventCountCircuitBreaker(int openingThreshold, long checkInterval, java.util.concurrent.TimeUnit checkUnit, int closingThreshold)
EventCountCircuitBreaker
with the same interval for opening
and closing checks.openingThreshold
- the threshold for opening the circuit breaker; if this
number of events is received in the time span determined by the check interval, the
circuit breaker is openedcheckInterval
- the check interval for opening or closing the circuit breakercheckUnit
- the TimeUnit
defining the check intervalclosingThreshold
- the threshold for closing the circuit breaker; if the
number of events received in the time span determined by the check interval goes
below this threshold, the circuit breaker is closed againpublic EventCountCircuitBreaker(int threshold, long checkInterval, java.util.concurrent.TimeUnit checkUnit)
EventCountCircuitBreaker
which uses the same parameters for
opening and closing checks.threshold
- the threshold for changing the status of the circuit breaker; if
the number of events received in a check interval is greater than this value, the
circuit breaker is opened; if it is lower than this value, it is closed againcheckInterval
- the check interval for opening or closing the circuit breakercheckUnit
- the TimeUnit
defining the check intervalpublic int getOpeningThreshold()
public long getOpeningInterval()
public int getClosingThreshold()
public long getClosingInterval()
public boolean checkState()
CLOSED
; a value
of true typically means that the current operation can continue. This implementation checks the internal event counter against the
threshold values and the check intervals. This may cause a state change of this
circuit breaker.checkState
in interface CircuitBreaker<java.lang.Integer>
checkState
in class AbstractCircuitBreaker<java.lang.Integer>
public boolean incrementAndCheckState(java.lang.Integer increment) throws CircuitBreakingException
CircuitBreaker.checkState()
, but the monitored
value is incremented before the state check is performed.incrementAndCheckState
in interface CircuitBreaker<java.lang.Integer>
incrementAndCheckState
in class AbstractCircuitBreaker<java.lang.Integer>
increment
- value to increment in the monitored value of the circuit breakerCircuitBreakingException
public boolean incrementAndCheckState()
checkState()
, but the monitored
value is incremented before the state check is performed.public void open()
open
in interface CircuitBreaker<java.lang.Integer>
open
in class AbstractCircuitBreaker<java.lang.Integer>
public void close()
close
in interface CircuitBreaker<java.lang.Integer>
close
in class AbstractCircuitBreaker<java.lang.Integer>
private boolean performStateCheck(int increment)
increment
- the increment for the internal counterprivate boolean updateCheckIntervalData(EventCountCircuitBreaker.CheckIntervalData currentData, EventCountCircuitBreaker.CheckIntervalData nextData)
CheckIntervalData
object. The current data object is replaced
by the one modified by the last check. The return value indicates whether this was
successful. If it is false, another thread interfered, and the
whole operation has to be redone.currentData
- the current check data objectnextData
- the replacing check data objectprivate void changeStateAndStartNewCheckInterval(AbstractCircuitBreaker.State newState)
CheckIntervalData
object.newState
- the new state to be setprivate EventCountCircuitBreaker.CheckIntervalData nextCheckIntervalData(int increment, EventCountCircuitBreaker.CheckIntervalData currentData, AbstractCircuitBreaker.State currentState, long time)
CheckIntervalData
object based on the current data and
the current state. The next data object takes the counter increment and the current
time into account.increment
- the increment for the internal countercurrentData
- the current check data objectcurrentState
- the current state of the circuit breakertime
- the current timeCheckIntervalData
objectlong now()
private static EventCountCircuitBreaker.StateStrategy stateStrategy(AbstractCircuitBreaker.State state)
StateStrategy
object responsible for the given state.state
- the stateStateStrategy
CircuitBreakingException
- if the strategy cannot be resolvedprivate static java.util.Map<AbstractCircuitBreaker.State,EventCountCircuitBreaker.StateStrategy> createStrategyMap()