diff --git a/akka-docs/src/main/paradox/common/circuitbreaker.md b/akka-docs/src/main/paradox/common/circuitbreaker.md index 220deae574..fce5d0b9c7 100644 --- a/akka-docs/src/main/paradox/common/circuitbreaker.md +++ b/akka-docs/src/main/paradox/common/circuitbreaker.md @@ -25,7 +25,7 @@ the site that use the functionality unavailable, or perhaps show some cached con appropriate while the breaker is open. The Akka library provides an implementation of a circuit breaker called -`akka.pattern.CircuitBreaker` which has the behavior described below. +@apidoc[CircuitBreaker] which has the behavior described below. ## What do they do? @@ -37,7 +37,7 @@ The Akka library provides an implementation of a circuit breaker called * While in *Open* state: - - All calls fail-fast with a `CircuitBreakerOpenException` + - All calls fail-fast with a @apidoc[CircuitBreakerOpenException] - After the configured *resetTimeout*, the circuit breaker enters a *Half-Open* state * In *Half-Open* state: @@ -49,14 +49,14 @@ The Akka library provides an implementation of a circuit breaker called * State transition listeners: - - Callbacks can be provided for every state entry via *onOpen*, *onClose*, and *onHalfOpen* - - These are executed in the `ExecutionContext` provided. + - Callbacks can be provided for every state entry via @apidoc[onOpen](CircuitBreaker) {scala="#onOpen(callback:=%3EUnit):akka.pattern.CircuitBreaker" java="#addOnOpenListener(java.lang.Runnable)"}, @apidoc[onClose](CircuitBreaker) {scala="#onClose(callback:=%3EUnit):akka.pattern.CircuitBreaker" java="#addOnCloseListener(java.lang.Runnable)"}, and @apidoc[onHalfOpen](CircuitBreaker) {scala="#onHalfOpen(callback:=%3EUnit):akka.pattern.CircuitBreaker" java="#addOnHalfOpenListener(java.lang.Runnable)"} + - These are executed in the @scaladoc[ExecutionContext](scala.concurrent.ExecutionContext) provided. * Calls result listeners: - Callbacks can be used eg. to collect statistics about all invocations or to react on specific call results like success, failures or timeouts. - - Supported callbacks are: *onCallSuccess*, *onCallFailure*, *onCallTimeout*, *onCallBreakerOpen*. - - These are executed in the `ExecutionContext` provided. + - Supported callbacks are: @apidoc[onCallSuccess](CircuitBreaker) {scala="#onCallSuccess(callback:Long=%3EUnit):akka.pattern.CircuitBreaker" java="#addOnCallSuccessListener(java.util.function.Consumer)"}, @apidoc[onCallFailure](CircuitBreaker) {scala="#onCallFailure(callback:Long=%3EUnit):akka.pattern.CircuitBreaker" java="#addOnCallFailureListener(java.util.function.Consumer)"}, @apidoc[onCallTimeout](CircuitBreaker) {scala="#onCallTimeout(callback:Long=%3EUnit):akka.pattern.CircuitBreaker" java="#addOnCallTimeoutListener(java.util.function.Consumer)"}, @apidoc[onCallBreakerOpen](CircuitBreaker) {scala="#onCallBreakerOpen(callback:=%3EUnit):akka.pattern.CircuitBreaker" java="#addOnCallBreakerOpenListener(java.lang.Runnable)"}. + - These are executed in the @scaladoc[ExecutionContext](scala.concurrent.ExecutionContext) provided. ![circuit-breaker-states.png](../images/circuit-breaker-states.png) @@ -65,7 +65,7 @@ The Akka library provides an implementation of a circuit breaker called ### Initialization -Here's how a `CircuitBreaker` would be configured for: +Here's how a @apidoc[CircuitBreaker] would be configured for: * 5 maximum failures * a call timeout of 10 seconds @@ -80,9 +80,9 @@ Java ### Future & Synchronous based API -Once a circuit breaker actor has been initialized, interacting with that actor is done by either using the Future based API or the synchronous API. Both of these APIs are considered `Call Protection` because whether synchronously or asynchronously, the purpose of the circuit breaker is to protect your system from cascading failures while making a call to another service. In the future based API, we use the `withCircuitBreaker` which takes an asynchronous method (some method wrapped in a `Future`), for instance a call to retrieve data from a database, and we pipe the result back to the sender. If for some reason the database in this example isn't responding, or there is another issue, the circuit breaker will open and stop trying to hit the database again and again until the timeout is over. +Once a circuit breaker actor has been initialized, interacting with that actor is done by either using the Future based API or the synchronous API. Both of these APIs are considered `Call Protection` because whether synchronously or asynchronously, the purpose of the circuit breaker is to protect your system from cascading failures while making a call to another service. In the future based API, we use the @scala[@scaladoc[withCircuitBreaker](akka.pattern.CircuitBreaker#withCircuitBreaker[T](body:=%3Escala.concurrent.Future[T]):scala.concurrent.Future[T])]@java[@javadoc[callWithCircuitBreakerCS](akka.pattern.CircuitBreaker#callWithCircuitBreakerCS(java.util.concurrent.Callable))] which takes an asynchronous method (some method wrapped in a @scala[@scaladoc[Future](scala.concurrent.Future)]@java[@javadoc[CompletionState](java.util.concurrent.CompletionStage)]), for instance a call to retrieve data from a database, and we pipe the result back to the sender. If for some reason the database in this example isn't responding, or there is another issue, the circuit breaker will open and stop trying to hit the database again and again until the timeout is over. -The Synchronous API would also wrap your call with the circuit breaker logic, however, it uses the `withSyncCircuitBreaker` and receives a method that is not wrapped in a `Future`. +The Synchronous API would also wrap your call with the circuit breaker logic, however, it uses the @scala[@scaladoc[withSyncCircuitBreaker](akka.pattern.CircuitBreaker#withSyncCircuitBreaker[T](body:=%3ET):T)]@java[@javadoc[callWithSyncCircuitBreaker](akka.pattern.CircuitBreaker#callWithSyncCircuitBreaker(java.util.concurrent.Callable))] and receives a method that is not wrapped in a @scala[@scaladoc[Future](scala.concurrent.Future)]@java[@javadoc[CompletionState](java.util.concurrent.CompletionStage)]. Scala : @@snip [CircuitBreakerDocSpec.scala](/akka-docs/src/test/scala/docs/circuitbreaker/CircuitBreakerDocSpec.scala) { #circuit-breaker-usage } @@ -92,33 +92,27 @@ Java @@@ note -Using the `CircuitBreaker`'s companion object @scala[*apply*]@java[*create*] method -will return a `CircuitBreaker` where callbacks are executed in the caller's thread. -This can be useful if the asynchronous `Future` behavior is unnecessary, for +Using the @scala[@apidoc[CircuitBreaker](CircuitBreaker$)'s companion object @scaladoc[apply](akka.pattern.CircuitBreaker$#apply(scheduler:akka.actor.Scheduler,maxFailures:Int,callTimeout:scala.concurrent.duration.FiniteDuration,resetTimeout:scala.concurrent.duration.FiniteDuration):akka.pattern.CircuitBreaker)]@java[@javadoc[CircuitBreaker.create](akka.pattern.CircuitBreaker#create(akka.actor.Scheduler,int,java.time.Duration,java.time.Duration))] method +will return a @apidoc[CircuitBreaker] where callbacks are executed in the caller's thread. +This can be useful if the asynchronous @scala[@scaladoc[Future](scala.concurrent.Future)]@java[@javadoc[CompletionState](java.util.concurrent.CompletionStage)] behavior is unnecessary, for example invoking a synchronous-only API. @@@ ### Control failure count explicitly -By default, the circuit breaker treats `Exception` as failure in synchronized API, or failed `Future` as failure in future based API. +By default, the circuit breaker treats @javadoc[Exception](java.lang.Exception) as failure in synchronized API, or failed @scala[@scaladoc[Future](scala.concurrent.Future)]@java[@javadoc[CompletionState](java.util.concurrent.CompletionStage)] as failure in future based API. On failure, the failure count will increment. If the failure count reaches the *maxFailures*, the circuit breaker will be opened. However, some applications may require certain exceptions to not increase the failure count. In other cases one may want to increase the failure count even if the call succeeded. -Akka circuit breaker provides a way to achieve such use cases: - -* `withCircuitBreaker` -* `withSyncCircuitBreaker` -* `callWithCircuitBreaker` -* `callWithCircuitBreakerCS` -* `callWithSyncCircuitBreaker` +Akka circuit breaker provides a way to achieve such use cases: @scala[@scaladoc[withCircuitBreaker](akka.pattern.CircuitBreaker#withCircuitBreaker[T](body:=%3Escala.concurrent.Future[T],defineFailureFn:scala.util.Try[T]=%3EBoolean):scala.concurrent.Future[T]) and @scaladoc[withSyncCircuitBreaker](akka.pattern.CircuitBreaker#withSyncCircuitBreaker[T](body:=%3ET,defineFailureFn:scala.util.Try[T]=%3EBoolean):T)]@java[@javadoc[callWithCircuitBreaker](akka.pattern.CircuitBreaker#callWithCircuitBreaker(java.util.concurrent.Callable,java.util.function.BiFunction)), @javadoc[callWithSyncCircuitBreaker](akka.pattern.CircuitBreaker#callWithSyncCircuitBreaker(java.util.concurrent.Callable,java.util.function.BiFunction)) and @javadoc[callWithCircuitBreakerCS](akka.pattern.CircuitBreaker#callWithCircuitBreakerCS(java.util.concurrent.Callable,java.util.function.BiFunction))]. All methods above accept an argument `defineFailureFn` -Type of `defineFailureFn`: @scala[`Try[T] => Boolean`]@java[`BiFunction[Optional[T], Optional[Throwable], java.lang.Boolean]`] +Type of `defineFailureFn`: @scala[@scaladoc[Try[T]](scala.util.Try) => @scaladoc[Boolean](scala.Boolean)]@java[@javadoc[BiFunction](java.util.function.BiFunction)[@javadoc[Optional[T]](java.util.Optional), @javadoc[Optional](java.util.Optional)[@javadoc[Throwable](java.lang.Throwable)], @javadoc[Boolean](java.lang.Boolean)]] -@scala[This is a function which takes in a `Try[T]` and returns a `Boolean`. The `Try[T]` correspond to the `Future[T]` of the protected call.] -@java[The response of a protected call is modelled using `Optional[T]` for a successful return value and `Optional[Throwable]` for exceptions.] This function should return `true` if the call should increase failure count, else false. +@scala[This is a function which takes in a @scaladoc[Try[T]](scala.util.Try) and returns a @scaladoc[Boolean](scala.Boolean). The @scaladoc[Try[T]](scala.util.Try) correspond to the @scaladoc[Future[T]](scala.concurrent.Future) of the protected call.] +@java[The response of a protected call is modelled using @javadoc[Optional[T]](java.util.Optional) for a successful return value and @javadoc[Optional](java.util.Optional)[@javadoc[Throwable](java.lang.Throwable)] for exceptions.] This function should return `true` if the call should increase failure count, else false. Scala : @@snip [CircuitBreakerDocSpec.scala](/akka-docs/src/test/scala/docs/circuitbreaker/CircuitBreakerDocSpec.scala) { #even-no-as-failure } @@ -128,14 +122,14 @@ Java ### Low level API -The low-level API allows you to describe the behavior of the CircuitBreaker in detail, including deciding what to return to the calling `Actor` in case of success or failure. This is especially useful when expecting the remote call to send a reply. -CircuitBreaker doesn't support `Tell Protection` (protecting against calls that expect a reply) natively at the moment. -Thus you need to use the low-level power-user APIs, `succeed` and `fail` methods, as well as `isClose`, `isOpen`, `isHalfOpen` to implement it. +The low-level API allows you to describe the behavior of the @apidoc[CircuitBreaker](CircuitBreaker) in detail, including deciding what to return to the calling @apidoc[Actor](Actor) in case of success or failure. This is especially useful when expecting the remote call to send a reply. +@apidoc[CircuitBreaker](CircuitBreaker) doesn't support `Tell Protection` (protecting against calls that expect a reply) natively at the moment. +Thus you need to use the low-level power-user APIs, @apidoc[succeed](CircuitBreaker) {scala="#succeed():Unit" java="#succeed()"} and @apidoc[fail](CircuitBreaker) {scala="#fail():Unit" java="#fail()"} methods, as well as @apidoc[isClosed](CircuitBreaker) {scala="#isClosed:Boolean" java="#isClosed()"}, @apidoc[isOpen](CircuitBreaker) {scala="#isOpen:Boolean" java="#isOpen()"}, @apidoc[isHalfOpen](CircuitBreaker) {scala="#isHalfOpen:Boolean" java="#isHalfOpen()"} to implement it. -As can be seen in the examples below, a `Tell Protection` pattern could be implemented by using the `succeed` and `fail` methods, which would count towards the `CircuitBreaker` counts. -In the example, a call is made to the remote service if the `breaker.isClosed`. -Once a response is received, the `succeed` method is invoked, which tells the `CircuitBreaker` to keep the breaker closed. -On the other hand, if an error or timeout is received we trigger a `fail`, and the breaker accrues this failure towards its count for opening the breaker. +As can be seen in the examples below, a `Tell Protection` pattern could be implemented by using the @apidoc[succeed](CircuitBreaker) {scala="#succeed():Unit" java="#succeed()"} and @apidoc[fail](CircuitBreaker) {scala="#fail():Unit" java="#fail()"} methods, which would count towards the @apidoc[CircuitBreaker](CircuitBreaker) counts. +In the example, a call is made to the remote service if the @apidoc[breaker.isClosed](CircuitBreaker) {scala="#isClosed:Boolean" java="#isClosed()"}. +Once a response is received, the @apidoc[succeed](CircuitBreaker) {scala="#succeed():Unit" java="#succeed()"} method is invoked, which tells the @apidoc[CircuitBreaker](CircuitBreaker) to keep the breaker closed. +On the other hand, if an error or timeout is received we trigger a @apidoc[fail](CircuitBreaker) {scala="#fail():Unit" java="#fail()"}, and the breaker accrues this failure towards its count for opening the breaker. @@@ note