A circuit breaker implementation in Scala
Scala
Switch branches/tags
Nothing to show
Latest commit e059353 May 22, 2017 @sptz45 Minor refinements.
Permalink
Failed to load latest commit information.
project
sbt-common @ 5f3dfd7 Use sse-sbt-common & upgrade scala versions. May 21, 2017
src
.gitignore Use sbt instead of maven. Apr 4, 2015
.gitmodules Use sse-sbt-common & upgrade scala versions. May 21, 2017
.travis.yml
LICENSE
NOTICE Added README, NOTICE and LICENSE files. Aug 18, 2010
README.md
build.sbt Minor refinements. May 22, 2017
version.sbt Add version.sbt file for sbt-release plugin. Apr 6, 2015

README.md

sse-breaker

Build Status

An implementation of the Circuit Breaker stability design pattern in the Scala programming language.

Description

At any point in time a circuit-breaker can be in any of the following three states: closed, open or half-open.

During normal operation a circuit-breaker is in the closed state and allows the execution of the requested operations recording the number of failures that happen as a result of those operations. A failure is either a thrown exception for which the configured CircuitConfiguration.isFailure function returns true or a successful operation execution that takes more than the configured CircuitConfiguration.maxMethodDuration duration to complete.

When the number of failures that occur within the configured CircuitConfiguration.failureCountTimeout duration exceeds the CircuitConfiguration.maxFailures then the circuit-breaker moves to the open state. In the open state, since the probability that failures will happen is high, the circuit-breaker does not permit the execution of any requested operation by failing fast. This is achieved by throwing an OpenCircuitException or by returning a failed Future that contains OpenCircuitException if the operation is asynchronous.

After the configured CircuitConfiguration.openCircuitTimeout duration has passed the circuit-breaker moves from the open to the half-open state. In this state when a request to execute an operation is made, the circuit breaker allows execution of the operation and if it succeeds it moves to the closed state, else it moves back to the open state.

Usage

To execute operations using a circuit-breaker you need to construct a CircuitExecutor and pass it the pieces of code you want to execute. This executor has an associated CircuitBreaker object which holds the state of the circuit-breaker and is consulted to decide whether to execute the requested operations or to fail-fast.

To construct a CircuitExecutor you can use the following code:

import com.tzavellas.sse.breaker.{CircuitExecutor, CircuitConfiguration}
import scala.concurrent.duration._

val failFast = new CircuitExecutor(
    circuitName="tweets-breaker",
    circuitConfig=CircuitConfiguration(
      maxFailures = 5,
      openCircuitTimeout = 30.seconds,
      failureCountTimeout = 1.minute,
      maxMethodDuration =  10.seconds)
  )

The above code will construct a CircuitExecutor with the name "tweets-breaker" using the specified configuration. The configuration says that if 5 failures (maxFailures) occur within 1 minute (failureCountTimeout) then the circuit breaker will move to the open state and move to the half-open state 30 seconds later (openCircuitTimeout). Also the maximum amount of time an operation might take without recording it as failure is 10 seconds (maxMethodDuration).

Using the executor with a synchronous operation:

def getTweets(user: String): Seq[Tweet] = ???

val tweets =
  try failFast { getTweets("sptz45") }
  catch { case e: OpenCircuitException => Seq() }

Using the executor with an asynchronous operation (one that returns a Future):

import scala.concurrent.{Future, ExecutionContext}

implicit val executionContext = ExecutionContext.fromExecutor(???)

def getTweetsAsync(user: String): Future[Seq[Tweet]] = ???

val tweets = failFast(getTweetsAsync("sptz45"))
               .recover { case _: OpenCircuitException => Seq() }

Using the executor by launching a synchronous operation in an ExecutionContext and returning a Future:

import scala.concurrent.{Future, ExecutionContext}

implicit val executionContext = ExecutionContext.fromExecutor(???)

def getTweets(user: String): Seq[Tweet] = ???

val tweets = failFast.async(getTweets("sptz45"))
               .recover { case _: OpenCircuitException => Seq() }

Setup

For Scala 2.10.x use:

<dependency>
  <groupId>com.tzavellas</groupId>
  <artifactId>sse-breaker</artifactId>
  <version>0.8.0</version>
</dependency>

License

Licensed under the Apache License, Version 2.0. See the LICENSE and NOTICE files for more information.