jcircuit

pure java impl of circuit breaker design pattern

Graceful, Robust Error Handling

Error handling is a complex topic. It's all well and good to throw exceptions, or to return EACCES, or to log problems--but how do you handle failures in the error handling code itself? How do you test alternate code paths? What happens if a spike in errors floods your logs, and the error handling logic is so expensive that it brings the rest of the system to its knees? What do you do if a system is unhealthy, but not definitively broken? How can you degrade behavior gracefully?

Circuit breakers are a useful approach to many of these concerns. They encapsulate orderly degradation and retry logic, and provide a simple interface for automation and testing.

More reading about circuit breakers and error handling: "Don't forget the circuit breakers" | "Good Code Plans for Problems" | "Why Your Software Should Cry" | "Know Your Limits" | "Add some more extra redundancy again"

About This Package

The jcircuit library is a tidy little package that implements the circuit breaker design pattern (as articulated by Michael Nygard in Release It!) with no external dependencies. It is compatible with java 6+. It is well tested, reasonably documented, and efficient even under very demanding concurrency. Plus it's free (MIT license). Please put it to work to make software better for all of us.

Getting Started

1. Add this block to the <dependencies> section of your pom.xml:

<dependency>
    <groupId>co.codecraft</groupId>
    <artifactId>jcircuit</artifactId>
    <version>1.0</version>
</dependency>

2. Create a CircuitBreaker to manage a codepath that needs to degrade gracefully:

private static CircuitBreaker savePayloadBreaker =
    new CircuitBreaker(
        TimedRatioPolicy.builder()
          .setEvalEveryNMillis(1000)  // check health 1x/sec
          .setOpenAtGoodRatio(0.5)    // if ok < 50% of time, trip
          .setCloseAtGoodRatio(0.7)   // close again if >= 70% ok
          .setResetAfterNMillis(5000) // try to reset after 5 secs
          .build());

3. Put the circuit breaker to work:

public void savePayload(Payload p) {
    // Let circuit breaker influence code path.
    // Tell it about outcome so it can update its state.
    if (savePayloadBreaker.shouldTryNormalPath()) {
        try {
            server.save(p); // we think we're healthy
            savePayloadBreaker.onGoodPulse(); // yep!
        } catch (ServerBusyException e) {
            savePayloadBreaker.onBadPulse(e); // warning sign
        }
    } else {
        savePayloadToTempFolder(p); // fallback logic
        savePayloadBreaker.onAltPulse();
    }
}

API Docs

An overview of key concepts, plus sample usage and descriptions of each class and method, can be found in the generated javadoc (or by reading the code).

Contribute

Many of the policy classes written to govern circuit breakers are going to be special purpose. However, we are interested in adding general-purpose ones to the jcircuit package. If you create one (or if you improve tests or fix a bug), please open a pull request so your brilliance and elbow grease can be shared with everyone.

We are unlikely to accept pull requests that introduce dependencies on this library, or that require versions of java later than java 6.