+htp #20198 onCompleteWithBreaker directive (#20402)

This commit is contained in:
Stefano Bonetti 2016-05-31 20:48:19 +01:00 committed by Konrad Malawski
parent f07041091f
commit 3f8dacfd44
14 changed files with 244 additions and 9 deletions

View file

@ -5,17 +5,17 @@
package docs.http.scaladsl.server.directives
import java.util.concurrent.TimeUnit
import akka.http.scaladsl.marshalling.ToResponseMarshallable
import docs.http.scaladsl.server.RoutingSpec
import scala.concurrent.Future
import scala.util.{ Success, Failure }
import akka.http.scaladsl.server.ExceptionHandler
import akka.actor.{ Actor, Props }
import scala.concurrent.duration._
import scala.util.{Failure, Success}
import akka.http.scaladsl.server.{CircuitBreakerOpenRejection, ExceptionHandler, Route}
import akka.util.Timeout
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Route
import StatusCodes._
import akka.pattern.CircuitBreaker
// format: OFF
@ -54,6 +54,47 @@ class FutureDirectivesExamplesSpec extends RoutingSpec {
}
}
"onCompleteWithBreaker" in {
def divide(a: Int, b: Int): Future[Int] = Future {
a / b
}
val resetTimeout = 1.second
val breaker = new CircuitBreaker(system.scheduler,
maxFailures = 1,
callTimeout = 5.seconds,
resetTimeout
)
val route =
path("divide" / IntNumber / IntNumber) { (a, b) =>
onCompleteWithBreaker(breaker)(divide(a, b)) {
case Success(value) => complete(s"The result was $value")
case Failure(ex) => complete((InternalServerError, s"An error occurred: ${ex.getMessage}"))
}
}
// tests:
Get("/divide/10/2") ~> route ~> check {
responseAs[String] shouldEqual "The result was 5"
}
Get("/divide/10/0") ~> Route.seal(route) ~> check {
status shouldEqual InternalServerError
responseAs[String] shouldEqual "An error occurred: / by zero"
} // opens the circuit breaker
Get("/divide/10/2") ~> route ~> check {
rejection shouldBe a[CircuitBreakerOpenRejection]
}
Thread.sleep(resetTimeout.toMillis + 200)
Get("/divide/10/2") ~> route ~> check {
responseAs[String] shouldEqual "The result was 5"
}
}
"onSuccess" in {
val route =
path("success") {

View file

@ -134,6 +134,9 @@ Directive Description
:ref:`-method-` Rejects all requests whose HTTP method does not match the given one
:ref:`-onComplete-` "Unwraps" a ``Future[T]`` and runs the inner route after future completion
with the future's value as an extraction of type ``Try[T]``
:ref:`-onCompleteWithBreaker-` "Unwraps" a ``Future[T]`` inside a ``CircuitBreaker`` and runs the inner
route after future completion with the future's value as an extraction of
type ``Try[T]``
:ref:`-onSuccess-` "Unwraps" a ``Future[T]`` and runs the inner route after future completion
with the future's value as an extraction of type ``T``
:ref:`-optionalCookie-` Extracts the ``HttpCookiePair`` with the given name as an

View file

@ -9,6 +9,7 @@ Future directives can be used to run inner routes once the provided ``Future[T]`
:maxdepth: 1
onComplete
onCompleteWithBreaker
onSuccess
completeOrRecoverWith

View file

@ -0,0 +1,27 @@
.. _-onCompleteWithBreaker-:
onCompleteWithBreaker
=====================
Signature
---------
.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/server/directives/FutureDirectives.scala
:snippet: onCompleteWithBreaker
Description
-----------
Evaluates its parameter of type ``Future[T]`` protecting it with the specified ``CircuitBreaker``.
Refer to :ref:`Akka Circuit Breaker<circuit-breaker>` for a detailed description of this pattern.
If the ``CircuitBreaker`` is open, the request is rejected with a ``CircuitBreakerOpenRejection``.
Note that in this case the request's entity databytes stream is cancelled, and the connection is closed
as a consequence.
Otherwise, the same behaviour provided by :ref:`-onComplete-` is to be expected.
Example
-------
.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/FutureDirectivesExamplesSpec.scala
:snippet: onCompleteWithBreaker