+doc,htc #18600,18597 documents where/how to deal with failure in Http
This commit is contained in:
parent
2f2e07666e
commit
573a69e2b9
20 changed files with 532 additions and 60 deletions
|
|
@ -3,20 +3,32 @@
|
|||
*/
|
||||
|
||||
package docs.http.scaladsl
|
||||
/*
|
||||
import scala.concurrent.Future
|
||||
import org.scalatest.{ WordSpec, Matchers }
|
||||
import akka.actor.ActorSystem
|
||||
|
||||
import akka.actor.{ ActorRef, ActorSystem }
|
||||
import akka.event.LoggingAdapter
|
||||
import akka.http.scaladsl.Http
|
||||
import akka.http.scaladsl.Http.ServerBinding
|
||||
import akka.http.scaladsl.model._
|
||||
import akka.stream.ActorMaterializer
|
||||
import akka.stream.scaladsl.{ Flow, Sink }
|
||||
import akka.stream.stage.{ Context, PushStage }
|
||||
import org.scalatest.{ Matchers, WordSpec }
|
||||
|
||||
import scala.concurrent.{ ExecutionContext, Future }
|
||||
|
||||
class HttpServerExampleSpec extends WordSpec with Matchers {
|
||||
|
||||
// never actually called
|
||||
val log: LoggingAdapter = null
|
||||
|
||||
"binding-example" in {
|
||||
import akka.http.scaladsl.Http
|
||||
import akka.stream.ActorMaterializer
|
||||
import akka.stream.scaladsl._
|
||||
import akka.http.scaladsl.Http
|
||||
|
||||
implicit val system = ActorSystem()
|
||||
implicit val materializer = ActorMaterializer()
|
||||
implicit val ec = system.dispatcher
|
||||
|
||||
val serverSource: Source[Http.IncomingConnection, Future[Http.ServerBinding]] =
|
||||
Http().bind(interface = "localhost", port = 8080)
|
||||
|
|
@ -27,12 +39,124 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
|
|||
}).run()
|
||||
}
|
||||
|
||||
"full-server-example" in {
|
||||
"binding-failure-high-level-example" in {
|
||||
import akka.http.scaladsl.Http
|
||||
import akka.http.scaladsl.server.Directives._
|
||||
import akka.stream.ActorMaterializer
|
||||
import akka.stream.scaladsl.Sink
|
||||
|
||||
implicit val system = ActorSystem()
|
||||
implicit val materializer = ActorMaterializer()
|
||||
implicit val ec = system.dispatcher
|
||||
|
||||
val handler = get {
|
||||
complete("Hello world!")
|
||||
}
|
||||
|
||||
// let's say the OS won't allow us to bind to 80.
|
||||
val (host, port) = ("localhost", 80)
|
||||
val bindingFuture: Future[ServerBinding] =
|
||||
Http().bindAndHandle(handler, host, port)
|
||||
|
||||
bindingFuture onFailure {
|
||||
case ex: Exception =>
|
||||
log.error(ex, "Failed to bind to {}:{}!", host, port)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// mock values:
|
||||
val handleConnections: Sink[Http.IncomingConnection, Future[Http.ServerBinding]] =
|
||||
Sink.ignore.mapMaterializedValue(_ => Future.failed(new Exception("")))
|
||||
|
||||
"binding-failure-handling" in {
|
||||
implicit val system = ActorSystem()
|
||||
implicit val materializer = ActorMaterializer()
|
||||
implicit val ec = system.dispatcher
|
||||
|
||||
// let's say the OS won't allow us to bind to 80.
|
||||
val (host, port) = ("localhost", 80)
|
||||
val serverSource = Http().bind(host, port)
|
||||
|
||||
val bindingFuture: Future[ServerBinding] = serverSource
|
||||
.to(handleConnections) // Sink[Http.IncomingConnection, _]
|
||||
.run()
|
||||
|
||||
bindingFuture onFailure {
|
||||
case ex: Exception =>
|
||||
log.error(ex, "Failed to bind to {}:{}!", host, port)
|
||||
}
|
||||
}
|
||||
|
||||
"incoming-connections-source-failure-handling" in {
|
||||
implicit val system = ActorSystem()
|
||||
implicit val materializer = ActorMaterializer()
|
||||
implicit val ec = system.dispatcher
|
||||
|
||||
import Http._
|
||||
val (host, port) = ("localhost", 8080)
|
||||
val serverSource = Http().bind(host, port)
|
||||
|
||||
val failureMonitor: ActorRef = ???
|
||||
|
||||
val reactToTopLevelFailures = Flow[IncomingConnection]
|
||||
.transform { () =>
|
||||
new PushStage[IncomingConnection, IncomingConnection] {
|
||||
override def onPush(elem: IncomingConnection, ctx: Context[IncomingConnection]) =
|
||||
ctx.push(elem)
|
||||
|
||||
override def onUpstreamFailure(cause: Throwable, ctx: Context[IncomingConnection]) = {
|
||||
failureMonitor ! cause
|
||||
super.onUpstreamFailure(cause, ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serverSource
|
||||
.via(reactToTopLevelFailures)
|
||||
.to(handleConnections) // Sink[Http.IncomingConnection, _]
|
||||
.run()
|
||||
}
|
||||
|
||||
"connection-stream-failure-handling" in {
|
||||
implicit val system = ActorSystem()
|
||||
implicit val materializer = ActorMaterializer()
|
||||
implicit val ec = system.dispatcher
|
||||
|
||||
val (host, port) = ("localhost", 8080)
|
||||
val serverSource = Http().bind(host, port)
|
||||
|
||||
val reactToConnectionFailure = Flow[HttpRequest]
|
||||
.transform { () =>
|
||||
new PushStage[HttpRequest, HttpRequest] {
|
||||
override def onPush(elem: HttpRequest, ctx: Context[HttpRequest]) =
|
||||
ctx.push(elem)
|
||||
|
||||
override def onUpstreamFailure(cause: Throwable, ctx: Context[HttpRequest]) = {
|
||||
// handle the failure somehow
|
||||
super.onUpstreamFailure(cause, ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val httpEcho = Flow[HttpRequest]
|
||||
.via(reactToConnectionFailure)
|
||||
.map { request =>
|
||||
// simple text "echo" response:
|
||||
HttpResponse(entity = HttpEntity(ContentTypes.`text/plain`, request.entity.dataBytes))
|
||||
}
|
||||
|
||||
serverSource
|
||||
.runForeach { con =>
|
||||
con.handleWith(httpEcho)
|
||||
}
|
||||
}
|
||||
|
||||
"full-server-example" in {
|
||||
import akka.http.scaladsl.Http
|
||||
import akka.http.scaladsl.model.HttpMethods._
|
||||
import akka.http.scaladsl.model._
|
||||
import akka.stream.ActorMaterializer
|
||||
import akka.stream.scaladsl.Sink
|
||||
|
||||
implicit val system = ActorSystem()
|
||||
implicit val materializer = ActorMaterializer()
|
||||
|
|
@ -65,10 +189,10 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
|
|||
}
|
||||
|
||||
"low-level-server-example" in {
|
||||
import akka.stream.ActorMaterializer
|
||||
import akka.http.scaladsl.Http
|
||||
import akka.http.scaladsl.model.HttpMethods._
|
||||
import akka.http.scaladsl.model._
|
||||
import akka.stream.ActorMaterializer
|
||||
|
||||
implicit val system = ActorSystem()
|
||||
implicit val materializer = ActorMaterializer()
|
||||
|
|
@ -94,10 +218,10 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
|
|||
// format: OFF
|
||||
|
||||
"high-level-server-example" in {
|
||||
import akka.stream.ActorMaterializer
|
||||
import akka.http.scaladsl.Http
|
||||
import akka.http.scaladsl.server.Directives._
|
||||
import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._
|
||||
import akka.http.scaladsl.server.Directives._
|
||||
import akka.stream.ActorMaterializer
|
||||
|
||||
implicit val system = ActorSystem()
|
||||
implicit val materializer = ActorMaterializer()
|
||||
|
|
@ -124,14 +248,15 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
|
|||
}
|
||||
|
||||
"minimal-routing-example" in {
|
||||
import akka.stream.ActorMaterializer
|
||||
import akka.http.scaladsl.Http
|
||||
import akka.http.scaladsl.server.Directives._
|
||||
import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._
|
||||
import akka.http.scaladsl.server.Directives._
|
||||
import akka.stream.ActorMaterializer
|
||||
|
||||
object Main extends App {
|
||||
implicit val system = ActorSystem("my-system")
|
||||
implicit val materializer = ActorMaterializer()
|
||||
implicit val ec = system.dispatcher
|
||||
|
||||
val route =
|
||||
path("hello") {
|
||||
|
|
@ -145,9 +270,7 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
|
|||
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
|
||||
|
||||
println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
|
||||
Console.readLine()
|
||||
|
||||
import system.dispatcher // for the future transformations
|
||||
Console.readLine() // for the future transformations
|
||||
bindingFuture
|
||||
.flatMap(_.unbind()) // trigger unbinding from the port
|
||||
.onComplete(_ ⇒ system.shutdown()) // and shutdown when done
|
||||
|
|
@ -156,13 +279,13 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
|
|||
|
||||
"long-routing-example" in {
|
||||
import akka.actor.ActorRef
|
||||
import akka.util.Timeout
|
||||
import akka.pattern.ask
|
||||
import akka.http.scaladsl.marshalling.ToResponseMarshaller
|
||||
import akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller
|
||||
import akka.http.scaladsl.model.StatusCodes.MovedPermanently
|
||||
import akka.http.scaladsl.coding.Deflate
|
||||
import akka.http.scaladsl.marshalling.ToResponseMarshaller
|
||||
import akka.http.scaladsl.model.StatusCodes.MovedPermanently
|
||||
import akka.http.scaladsl.server.Directives._
|
||||
import akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller
|
||||
import akka.pattern.ask
|
||||
import akka.util.Timeout
|
||||
|
||||
// types used by the API routes
|
||||
type Money = Double // only for demo purposes, don't try this at home!
|
||||
|
|
@ -174,6 +297,9 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
|
|||
implicit val orderUM: FromRequestUnmarshaller[Order] = ???
|
||||
implicit val orderM: ToResponseMarshaller[Seq[Order]] = ???
|
||||
implicit val timeout: Timeout = ??? // for actor asks
|
||||
implicit val ec: ExecutionContext = ???
|
||||
implicit val mat: ActorMaterializer = ???
|
||||
implicit val sys: ActorSystem = ???
|
||||
|
||||
val route = {
|
||||
path("orders") {
|
||||
|
|
@ -255,4 +381,3 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
|
|||
def processOrderRequest(id: Int, complete: Order => Unit): Unit = ???
|
||||
}
|
||||
}
|
||||
*/
|
||||
Loading…
Add table
Add a link
Reference in a new issue