/sse-breaker

A circuit breaker implementation in Scala

Primary LanguageScalaApache License 2.0Apache-2.0

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.