diff --git a/akka-docs/rst/common/circuitbreaker.rst b/akka-docs/rst/common/circuitbreaker.rst index 89f22cfbde..c33808836c 100644 --- a/akka-docs/rst/common/circuitbreaker.rst +++ b/akka-docs/rst/common/circuitbreaker.rst @@ -32,9 +32,9 @@ appropriate while the breaker is open. The Akka library provides an implementation of a circuit breaker called :class:`akka.pattern.CircuitBreaker` which has the behavior described below. -================= +================ What do they do? -================= +================ * During normal operation, a circuit breaker is in the `Closed` state: * Exceptions or calls exceeding the configured `callTimeout` increment a failure counter * Successes reset the failure count to zero @@ -119,6 +119,48 @@ Java There is also a :class:`CircuitBreakerProxy` actor that you can use, which is an alternative implementation of the pattern. The main difference is that it is intended to be used only for request-reply interactions with another actor. See :ref:`Circuit Breaker Actor ` +-------------------------------- +Control failure count explicitly +-------------------------------- + +By default, the circuit breaker treat :class:`Exception` as failure in synchronized API, or failed :class:`Future` as failure in future based API. +Failure will increment failure count, when failure count reach the `maxFailures`, circuit breaker will be opened. +However, some applications might requires certain exception to not increase failure count, or vice versa, +sometime we want to increase the failure count even if the call succeeded. +Akka circuit breaker provides a way to achieve such use case: + + * `withCircuitBreaker` + * `withSyncCircuitBreaker` + + * `callWithCircuitBreaker` + * `callWithCircuitBreakerCS` + * `callWithSyncCircuitBreaker` + +All methods above accepts an argument ``defineFailureFn`` + +~~~~~ +Scala +~~~~~ + +Type of ``defineFailureFn``: ``Try[T] ⇒ Boolean`` + +This is a function which takes in a :class:`Try[T]` and return a :class:`Boolean`. The :class:`Try[T]` correspond to the :class:`Future[T]` of the protected call. This function should return ``true`` if the call should increase failure count, else false. + +.. includecode:: code/docs/circuitbreaker/CircuitBreakerDocSpec.scala + :include: even-no-as-failure + +~~~~ +Java +~~~~ + +Type of ``defineFailureFn``: :class:`BiFunction[Optional[T], Optional[Throwable], java.lang.Boolean]` + +For Java Api, the signature is a bit different as there's no :class:`Try` in Java, so the response of protected call is modelled using :class:`Optional[T]` for succeeded return value and :class:`Optional[Throwable]` for exception, and the rules of return type is the same. +Ie. this function should return ``true`` if the call should increase failure count, else false. + +.. includecode:: code/docs/circuitbreaker/EvenNoFailureJavaExample.java + :include: even-no-as-failure + ------------- Low level API ------------- @@ -140,9 +182,9 @@ Scala :include: circuit-breaker-tell-pattern -~~~~~ +~~~~ Java -~~~~~ +~~~~ .. includecode:: code/docs/circuitbreaker/TellPatternJavaActor.java :include: circuit-breaker-tell-pattern diff --git a/akka-docs/rst/common/code/docs/circuitbreaker/CircuitBreakerDocSpec.scala b/akka-docs/rst/common/code/docs/circuitbreaker/CircuitBreakerDocSpec.scala index c1d51228bc..7c21856140 100644 --- a/akka-docs/rst/common/code/docs/circuitbreaker/CircuitBreakerDocSpec.scala +++ b/akka-docs/rst/common/code/docs/circuitbreaker/CircuitBreakerDocSpec.scala @@ -11,6 +11,7 @@ import akka.pattern.pipe import akka.actor.{ Actor, ActorLogging, ActorRef } import scala.concurrent.Future +import scala.util.{ Failure, Success, Try } //#imports1 @@ -76,3 +77,29 @@ class TellPatternActor(recipient: ActorRef) extends Actor with ActorLogging { } //#circuit-breaker-tell-pattern } + +class EvenNoFailureActor extends Actor { + import context.dispatcher + //#even-no-as-failure + def luckyNumber(): Future[Int] = { + val evenNumberAsFailure: Try[Int] => Boolean = { + case Success(n) => n % 2 == 0 + case Failure(_) => true + } + + val breaker = + new CircuitBreaker( + context.system.scheduler, + maxFailures = 5, + callTimeout = 10.seconds, + resetTimeout = 1.minute) + + // this call will return 8888 and increase failure count at the same time + breaker.withCircuitBreaker(Future(8888), evenNumberAsFailure) + } + //#even-no-as-failure + + override def receive = { + case x: Int => + } +} diff --git a/akka-docs/rst/common/code/docs/circuitbreaker/EvenNoFailureJavaExample.java b/akka-docs/rst/common/code/docs/circuitbreaker/EvenNoFailureJavaExample.java new file mode 100644 index 0000000000..e1536e8581 --- /dev/null +++ b/akka-docs/rst/common/code/docs/circuitbreaker/EvenNoFailureJavaExample.java @@ -0,0 +1,33 @@ +package docs.circuitbreaker; + +import akka.actor.AbstractActor; +import akka.pattern.CircuitBreaker; +import scala.concurrent.duration.Duration; + +import java.util.Optional; +import java.util.function.BiFunction; + +public class EvenNoFailureJavaExample extends AbstractActor { + //#even-no-as-failure + private final CircuitBreaker breaker; + + public EvenNoFailureJavaExample() { + this.breaker = new CircuitBreaker( + getContext().dispatcher(), getContext().system().scheduler(), + 5, Duration.create(10, "s"), Duration.create(1, "m")); + } + + public int luckyNumber() { + BiFunction, Optional, Boolean> evenNoAsFailure = + (result, err) -> (result.isPresent() && result.get() % 2 == 0); + + // this will return 8888 and increase failure count at the same time + return this.breaker.callWithSyncCircuitBreaker(() -> 8888, evenNoAsFailure); + } + + //#even-no-as-failure + @Override + public Receive createReceive() { + return null; + } +}