/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.lang3.concurrent;

import java.util.EnumMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

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:

  • A threshold for the number of events that causes a state transition to open state. If more events are received in the configured check interval, the circuit breaker switches to open state.
  • The interval for checks whether the circuit breaker should open. So it is possible to specify something like "The circuit breaker should open if more than 10 errors are encountered in a minute."
  • The same parameters can be specified for automatically closing the circuit breaker again, as in "If the number of requests goes down to 100 per minute, the circuit breaker should close itself again". Depending on the use case, it may make sense to use a slightly lower threshold for closing the circuit breaker than for opening it to avoid continuously flipping when the number of events received is close to the threshold.

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:

  • This implementation uses non-blocking algorithms to update the internal counter and state. This should be pretty efficient if there is not too much contention.
  • This implementation is not intended to operate as a high-precision timer in very short check intervals. It is deliberately kept simple to avoid complex and time-consuming state checks. It should work well in time intervals from a few seconds up to minutes and longer. If the intervals become too short, there might be race conditions causing spurious state transitions.
  • The handling of check intervals is a bit simplistic. Therefore, there is no guarantee that the circuit breaker is triggered at a specific point in time; there may be some delay (less than a check interval).
Since:3.5
/** * <p> * A simple implementation of the <a * href="http://martinfowler.com/bliki/CircuitBreaker.html">Circuit Breaker</a> pattern * that counts specific events. * </p> * <p> * A <em>circuit breaker</em> can be used to protect an application against unreliable * services or unexpected load. A newly created {@code EventCountCircuitBreaker} object is * initially in state <em>closed</em> 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 <em>open</em>. 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 <em>closed</em> state after a * certain time frame if the number of events received goes below a threshold. * </p> * <p> * When a {@code EventCountCircuitBreaker} object is constructed the following parameters * can be provided: * </p> * <ul> * <li>A threshold for the number of events that causes a state transition to * <em>open</em> state. If more events are received in the configured check interval, the * circuit breaker switches to <em>open</em> state.</li> * <li>The interval for checks whether the circuit breaker should open. So it is possible * to specify something like "The circuit breaker should open if more than 10 errors are * encountered in a minute."</li> * <li>The same parameters can be specified for automatically closing the circuit breaker * again, as in "If the number of requests goes down to 100 per minute, the circuit * breaker should close itself again". Depending on the use case, it may make sense to use * a slightly lower threshold for closing the circuit breaker than for opening it to avoid * continuously flipping when the number of events received is close to the threshold.</li> * </ul> * <p> * This class supports the following typical use cases: * </p> * <p> * <strong>Protecting against load peaks</strong> * </p> * <p> * 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 * {@code 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 {@code 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 <em>closed</em>: * </p> * * <pre> * 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 * } * } * </pre> * <p> * <strong>Deal with an unreliable service</strong> * </p> * <p> * 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: * </p> * * <pre> * 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. * } * } * </pre> * <p> * In addition to automatic state transitions, the state of a circuit breaker can be * changed manually using the methods {@link #open()} and {@link #close()}. It is also * possible to register {@code PropertyChangeListener} objects that get notified whenever * a state transition occurs. This is useful, for instance to directly react on a freshly * detected error condition. * </p> * <p> * <em>Implementation notes:</em> * </p> * <ul> * <li>This implementation uses non-blocking algorithms to update the internal counter and * state. This should be pretty efficient if there is not too much contention.</li> * <li>This implementation is not intended to operate as a high-precision timer in very * short check intervals. It is deliberately kept simple to avoid complex and * time-consuming state checks. It should work well in time intervals from a few seconds * up to minutes and longer. If the intervals become too short, there might be race * conditions causing spurious state transitions.</li> * <li>The handling of check intervals is a bit simplistic. Therefore, there is no * guarantee that the circuit breaker is triggered at a specific point in time; there may * be some delay (less than a check interval).</li> * </ul> * @since 3.5 */
public class EventCountCircuitBreaker extends AbstractCircuitBreaker<Integer> {
A map for accessing the strategy objects for the different states.
/** A map for accessing the strategy objects for the different states. */
private static final Map<State, StateStrategy> STRATEGY_MAP = createStrategyMap();
Stores information about the current check interval.
/** Stores information about the current check interval. */
private final AtomicReference<CheckIntervalData> checkIntervalData;
The threshold for opening the circuit breaker.
/** The threshold for opening the circuit breaker. */
private final int openingThreshold;
The time interval for opening the circuit breaker.
/** The time interval for opening the circuit breaker. */
private final long openingInterval;
The threshold for closing the circuit breaker.
/** The threshold for closing the circuit breaker. */
private final int closingThreshold;
The time interval for closing the circuit breaker.
/** The time interval for closing the circuit breaker. */
private final long closingInterval;
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.
Params:
  • 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 opened
  • openingInterval – the interval for opening the circuit breaker
  • openingUnit – the TimeUnit defining the opening interval
  • closingThreshold – 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 again
  • closingInterval – the interval for closing the circuit breaker
  • closingUnit – the TimeUnit defining the closing interval
/** * Creates a new instance of {@code EventCountCircuitBreaker} and initializes all properties for * opening and closing it based on threshold values for events occurring in specific * intervals. * * @param 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 opened * @param openingInterval the interval for opening the circuit breaker * @param openingUnit the {@code TimeUnit} defining the opening interval * @param closingThreshold 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 again * @param closingInterval the interval for closing the circuit breaker * @param closingUnit the {@code TimeUnit} defining the closing interval */
public EventCountCircuitBreaker(final int openingThreshold, final long openingInterval, final TimeUnit openingUnit, final int closingThreshold, final long closingInterval, final TimeUnit closingUnit) { super(); checkIntervalData = new AtomicReference<>(new CheckIntervalData(0, 0)); this.openingThreshold = openingThreshold; this.openingInterval = openingUnit.toNanos(openingInterval); this.closingThreshold = closingThreshold; this.closingInterval = closingUnit.toNanos(closingInterval); }
Creates a new instance of EventCountCircuitBreaker with the same interval for opening and closing checks.
Params:
  • 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 opened
  • checkInterval – the check interval for opening or closing the circuit breaker
  • checkUnit – the TimeUnit defining the check interval
  • closingThreshold – 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 again
/** * Creates a new instance of {@code EventCountCircuitBreaker} with the same interval for opening * and closing checks. * * @param 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 opened * @param checkInterval the check interval for opening or closing the circuit breaker * @param checkUnit the {@code TimeUnit} defining the check interval * @param closingThreshold 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 again */
public EventCountCircuitBreaker(final int openingThreshold, final long checkInterval, final TimeUnit checkUnit, final int closingThreshold) { this(openingThreshold, checkInterval, checkUnit, closingThreshold, checkInterval, checkUnit); }
Creates a new instance of EventCountCircuitBreaker which uses the same parameters for opening and closing checks.
Params:
  • 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 again
  • checkInterval – the check interval for opening or closing the circuit breaker
  • checkUnit – the TimeUnit defining the check interval
/** * Creates a new instance of {@code EventCountCircuitBreaker} which uses the same parameters for * opening and closing checks. * * @param 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 again * @param checkInterval the check interval for opening or closing the circuit breaker * @param checkUnit the {@code TimeUnit} defining the check interval */
public EventCountCircuitBreaker(final int threshold, final long checkInterval, final TimeUnit checkUnit) { this(threshold, checkInterval, checkUnit, threshold); }
Returns the threshold value 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 opened.
Returns:the opening threshold
/** * Returns the threshold value 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 opened. * * @return the opening threshold */
public int getOpeningThreshold() { return openingThreshold; }
Returns the interval (in nanoseconds) for checking for the opening threshold.
Returns:the opening check interval
/** * Returns the interval (in nanoseconds) for checking for the opening threshold. * * @return the opening check interval */
public long getOpeningInterval() { return openingInterval; }
Returns the threshold value 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 again.
Returns:the closing threshold
/** * Returns the threshold value 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 again. * * @return the closing threshold */
public int getClosingThreshold() { return closingThreshold; }
Returns the interval (in nanoseconds) for checking for the closing threshold.
Returns:the opening check interval
/** * Returns the interval (in nanoseconds) for checking for the closing threshold. * * @return the opening check interval */
public long getClosingInterval() { return closingInterval; }
{@inheritDoc} 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.
/** * {@inheritDoc} 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. */
@Override public boolean checkState() { return performStateCheck(0); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override public boolean incrementAndCheckState(final Integer increment) throws CircuitBreakingException { return performStateCheck(1); }
Increments the monitored value by 1 and performs a check of the current state of this circuit breaker. This method works like checkState(), but the monitored value is incremented before the state check is performed.
Returns:true if the circuit breaker is now closed; false otherwise
/** * Increments the monitored value by <strong>1</strong> and performs a check of the current state of this * circuit breaker. This method works like {@link #checkState()}, but the monitored * value is incremented before the state check is performed. * * @return <strong>true</strong> if the circuit breaker is now closed; * <strong>false</strong> otherwise */
public boolean incrementAndCheckState() { return incrementAndCheckState(1); }
{@inheritDoc} This circuit breaker may close itself again if the number of events received during a check interval goes below the closing threshold. If this circuit breaker is already open, this method has no effect, except that a new check interval is started.
/** * {@inheritDoc} This circuit breaker may close itself again if the number of events * received during a check interval goes below the closing threshold. If this circuit * breaker is already open, this method has no effect, except that a new check * interval is started. */
@Override public void open() { super.open(); checkIntervalData.set(new CheckIntervalData(0, now())); }
{@inheritDoc} A new check interval is started. If too many events are received in this interval, the circuit breaker changes again to state open. If this circuit breaker is already closed, this method has no effect, except that a new check interval is started.
/** * {@inheritDoc} A new check interval is started. If too many events are received in * this interval, the circuit breaker changes again to state open. If this circuit * breaker is already closed, this method has no effect, except that a new check * interval is started. */
@Override public void close() { super.close(); checkIntervalData.set(new CheckIntervalData(0, now())); }
Actually checks the state of this circuit breaker and executes a state transition if necessary.
Params:
  • increment – the increment for the internal counter
Returns:a flag whether the circuit breaker is now closed
/** * Actually checks the state of this circuit breaker and executes a state transition * if necessary. * * @param increment the increment for the internal counter * @return a flag whether the circuit breaker is now closed */
private boolean performStateCheck(final int increment) { CheckIntervalData currentData; CheckIntervalData nextData; State currentState; do { final long time = now(); currentState = state.get(); currentData = checkIntervalData.get(); nextData = nextCheckIntervalData(increment, currentData, currentState, time); } while (!updateCheckIntervalData(currentData, nextData)); // This might cause a race condition if other changes happen in between! // Refer to the header comment! if (stateStrategy(currentState).isStateTransition(this, currentData, nextData)) { currentState = currentState.oppositeState(); changeStateAndStartNewCheckInterval(currentState); } return !isOpen(currentState); }
Updates the 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.
Params:
  • currentData – the current check data object
  • nextData – the replacing check data object
Returns:a flag whether the update was successful
/** * Updates the {@code 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 <strong>false</strong>, another thread interfered, and the * whole operation has to be redone. * * @param currentData the current check data object * @param nextData the replacing check data object * @return a flag whether the update was successful */
private boolean updateCheckIntervalData(final CheckIntervalData currentData, final CheckIntervalData nextData) { return currentData == nextData || checkIntervalData.compareAndSet(currentData, nextData); }
Changes the state of this circuit breaker and also initializes a new CheckIntervalData object.
Params:
  • newState – the new state to be set
/** * Changes the state of this circuit breaker and also initializes a new * {@code CheckIntervalData} object. * * @param newState the new state to be set */
private void changeStateAndStartNewCheckInterval(final State newState) { changeState(newState); checkIntervalData.set(new CheckIntervalData(0, now())); }
Calculates the next 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.
Params:
  • increment – the increment for the internal counter
  • currentData – the current check data object
  • currentState – the current state of the circuit breaker
  • time – the current time
Returns:the updated CheckIntervalData object
/** * Calculates the next {@code 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. * * @param increment the increment for the internal counter * @param currentData the current check data object * @param currentState the current state of the circuit breaker * @param time the current time * @return the updated {@code CheckIntervalData} object */
private CheckIntervalData nextCheckIntervalData(final int increment, final CheckIntervalData currentData, final State currentState, final long time) { CheckIntervalData nextData; if (stateStrategy(currentState).isCheckIntervalFinished(this, currentData, time)) { nextData = new CheckIntervalData(increment, time); } else { nextData = currentData.increment(increment); } return nextData; }
Returns the current time in nanoseconds. This method is used to obtain the current time. This is needed to calculate the check intervals correctly.
Returns:the current time in nanoseconds
/** * Returns the current time in nanoseconds. This method is used to obtain the current * time. This is needed to calculate the check intervals correctly. * * @return the current time in nanoseconds */
long now() { return System.nanoTime(); }
Returns the StateStrategy object responsible for the given state.
Params:
  • state – the state
Throws:
Returns:the corresponding StateStrategy
/** * Returns the {@code StateStrategy} object responsible for the given state. * * @param state the state * @return the corresponding {@code StateStrategy} * @throws CircuitBreakingException if the strategy cannot be resolved */
private static StateStrategy stateStrategy(final State state) { return STRATEGY_MAP.get(state); }
Creates the map with strategy objects. It allows access for a strategy for a given state.
Returns:the strategy map
/** * Creates the map with strategy objects. It allows access for a strategy for a given * state. * * @return the strategy map */
private static Map<State, StateStrategy> createStrategyMap() { final Map<State, StateStrategy> map = new EnumMap<>(State.class); map.put(State.CLOSED, new StateStrategyClosed()); map.put(State.OPEN, new StateStrategyOpen()); return map; }
An internally used data class holding information about the checks performed by this class. Basically, the number of received events and the start time of the current check interval are stored.
/** * An internally used data class holding information about the checks performed by * this class. Basically, the number of received events and the start time of the * current check interval are stored. */
private static class CheckIntervalData {
The counter for events.
/** The counter for events. */
private final int eventCount;
The start time of the current check interval.
/** The start time of the current check interval. */
private final long checkIntervalStart;
Creates a new instance of CheckIntervalData.
Params:
  • count – the current count value
  • intervalStart – the start time of the check interval
/** * Creates a new instance of {@code CheckIntervalData}. * * @param count the current count value * @param intervalStart the start time of the check interval */
CheckIntervalData(final int count, final long intervalStart) { eventCount = count; checkIntervalStart = intervalStart; }
Returns the event counter.
Returns:the number of received events
/** * Returns the event counter. * * @return the number of received events */
public int getEventCount() { return eventCount; }
Returns the start time of the current check interval.
Returns:the check interval start time
/** * Returns the start time of the current check interval. * * @return the check interval start time */
public long getCheckIntervalStart() { return checkIntervalStart; }
Returns a new instance of CheckIntervalData with the event counter incremented by the given delta. If the delta is 0, this object is returned.
Params:
  • delta – the delta
Returns:the updated instance
/** * Returns a new instance of {@code CheckIntervalData} with the event counter * incremented by the given delta. If the delta is 0, this object is returned. * * @param delta the delta * @return the updated instance */
public CheckIntervalData increment(final int delta) { return (delta != 0) ? new CheckIntervalData(getEventCount() + delta, getCheckIntervalStart()) : this; } }
Internally used class for executing check logic based on the current state of the circuit breaker. Having this logic extracted into special classes avoids complex if-then-else cascades.
/** * Internally used class for executing check logic based on the current state of the * circuit breaker. Having this logic extracted into special classes avoids complex * if-then-else cascades. */
private abstract static class StateStrategy {
Returns a flag whether the end of the current check interval is reached.
Params:
  • breaker – the CircuitBreaker
  • currentData – the current state object
  • now – the current time
Returns:a flag whether the end of the current check interval is reached
/** * Returns a flag whether the end of the current check interval is reached. * * @param breaker the {@code CircuitBreaker} * @param currentData the current state object * @param now the current time * @return a flag whether the end of the current check interval is reached */
public boolean isCheckIntervalFinished(final EventCountCircuitBreaker breaker, final CheckIntervalData currentData, final long now) { return now - currentData.getCheckIntervalStart() > fetchCheckInterval(breaker); }
Checks whether the specified CheckIntervalData objects indicate that a state transition should occur. Here the logic which checks for thresholds depending on the current state is implemented.
Params:
  • breaker – the CircuitBreaker
  • currentData – the current CheckIntervalData object
  • nextData – the updated CheckIntervalData object
Returns:a flag whether a state transition should be performed
/** * Checks whether the specified {@code CheckIntervalData} objects indicate that a * state transition should occur. Here the logic which checks for thresholds * depending on the current state is implemented. * * @param breaker the {@code CircuitBreaker} * @param currentData the current {@code CheckIntervalData} object * @param nextData the updated {@code CheckIntervalData} object * @return a flag whether a state transition should be performed */
public abstract boolean isStateTransition(EventCountCircuitBreaker breaker, CheckIntervalData currentData, CheckIntervalData nextData);
Obtains the check interval to applied for the represented state from the given CircuitBreaker.
Params:
  • breaker – the CircuitBreaker
Returns:the check interval to be applied
/** * Obtains the check interval to applied for the represented state from the given * {@code CircuitBreaker}. * * @param breaker the {@code CircuitBreaker} * @return the check interval to be applied */
protected abstract long fetchCheckInterval(EventCountCircuitBreaker breaker); }
A specialized StateStrategy implementation for the state closed.
/** * A specialized {@code StateStrategy} implementation for the state closed. */
private static class StateStrategyClosed extends StateStrategy {
{@inheritDoc}
/** * {@inheritDoc} */
@Override public boolean isStateTransition(final EventCountCircuitBreaker breaker, final CheckIntervalData currentData, final CheckIntervalData nextData) { return nextData.getEventCount() > breaker.getOpeningThreshold(); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected long fetchCheckInterval(final EventCountCircuitBreaker breaker) { return breaker.getOpeningInterval(); } }
A specialized StateStrategy implementation for the state open.
/** * A specialized {@code StateStrategy} implementation for the state open. */
private static class StateStrategyOpen extends StateStrategy {
{@inheritDoc}
/** * {@inheritDoc} */
@Override public boolean isStateTransition(final EventCountCircuitBreaker breaker, final CheckIntervalData currentData, final CheckIntervalData nextData) { return nextData.getCheckIntervalStart() != currentData .getCheckIntervalStart() && currentData.getEventCount() < breaker.getClosingThreshold(); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override protected long fetchCheckInterval(final EventCountCircuitBreaker breaker) { return breaker.getClosingInterval(); } } }