+doc,htc #18600,18597 documents where/how to deal with failure in Http

This commit is contained in:
Konrad Malawski 2015-09-29 23:08:11 +02:00
parent 2f2e07666e
commit 573a69e2b9
20 changed files with 532 additions and 60 deletions

View file

@ -1,10 +1,10 @@
.. _stream-java-api:
Java Documentation
===================
==================
.. toctree::
:maxdepth: 2
:maxdepth: 3
java/stream-index
java/http/index

View file

@ -0,0 +1,39 @@
/*
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.http.javadsl.server;
//#binding-failure-high-level-example
import akka.actor.ActorSystem;
import akka.dispatch.OnFailure;
import akka.http.javadsl.model.ContentTypes;
import akka.http.javadsl.server.*;
import akka.http.javadsl.server.values.Parameters;
import akka.http.scaladsl.Http;
import scala.concurrent.Future;
import java.io.IOException;
@SuppressWarnings("unchecked")
public class HighLevelServerBindFailureExample {
public static void main(String[] args) throws IOException {
// boot up server using the route as defined below
final ActorSystem system = ActorSystem.create();
// HttpApp.bindRoute expects a route being provided by HttpApp.createRoute
Future<Http.ServerBinding> bindingFuture =
new HighLevelServerExample().bindRoute("localhost", 8080, system);
bindingFuture.onFailure(new OnFailure() {
@Override
public void onFailure(Throwable failure) throws Throwable {
System.err.println("Something very bad happened! " + failure.getMessage());
system.shutdown();
}
});
system.shutdown();
}
}
//#binding-failure-high-level-example

View file

@ -5,26 +5,43 @@
package docs.http.javadsl.server;
import akka.actor.ActorSystem;
import akka.dispatch.OnFailure;
import akka.http.impl.util.JavaMapping;
import akka.http.impl.util.Util;
import akka.http.javadsl.Http;
import akka.http.javadsl.IncomingConnection;
import akka.http.javadsl.ServerBinding;
import akka.http.javadsl.model.*;
import akka.http.javadsl.model.ContentTypes;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.HttpResponse;
import akka.http.javadsl.model.Uri;
import akka.japi.JavaPartialFunction;
import akka.japi.function.Function;
import akka.japi.function.Procedure;
import akka.stream.ActorMaterializer;
import akka.stream.Materializer;
import akka.stream.javadsl.Flow;
import akka.stream.javadsl.Sink;
import akka.stream.javadsl.Source;
import akka.stream.stage.Context;
import akka.stream.stage.PushStage;
import akka.stream.stage.SyncDirective;
import akka.stream.stage.TerminationDirective;
import akka.util.ByteString;
import scala.Function1;
import scala.concurrent.Await;
import scala.concurrent.Future;
import scala.concurrent.duration.FiniteDuration;
import scala.runtime.BoxedUnit;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;
@SuppressWarnings("unused")
public class HttpServerExampleDocTest {
public static void bindingExample() throws Exception {
//#binding-example
ActorSystem system = ActorSystem.create();
@ -45,6 +62,116 @@ public class HttpServerExampleDocTest {
//#binding-example
Await.result(serverBindingFuture, new FiniteDuration(3, TimeUnit.SECONDS));
}
public static void bindingFailureExample() throws Exception {
//#binding-failure-handling
ActorSystem system = ActorSystem.create();
Materializer materializer = ActorMaterializer.create(system);
Source<IncomingConnection, Future<ServerBinding>> serverSource =
Http.get(system).bind("localhost", 80, materializer);
Future<ServerBinding> serverBindingFuture =
serverSource.to(Sink.foreach(
new Procedure<IncomingConnection>() {
@Override
public void apply(IncomingConnection connection) throws Exception {
System.out.println("Accepted new connection from " + connection.remoteAddress());
// ... and then actually handle the connection
}
})).run(materializer);
serverBindingFuture.onFailure(new OnFailure() {
@Override
public void onFailure(Throwable failure) throws Throwable {
// possibly report the failure somewhere...
}
}, system.dispatcher());
//#binding-failure-handling
Await.result(serverBindingFuture, new FiniteDuration(3, TimeUnit.SECONDS));
}
public static void connectionSourceFailureExample() throws Exception {
//#incoming-connections-source-failure-handling
ActorSystem system = ActorSystem.create();
Materializer materializer = ActorMaterializer.create(system);
Source<IncomingConnection, Future<ServerBinding>> serverSource =
Http.get(system).bind("localhost", 8080, materializer);
Flow<IncomingConnection, IncomingConnection, BoxedUnit> failureDetection =
Flow.of(IncomingConnection.class).transform(() ->
new PushStage<IncomingConnection, IncomingConnection>() {
@Override
public SyncDirective onPush(IncomingConnection elem, Context<IncomingConnection> ctx) {
return ctx.push(elem);
}
@Override
public TerminationDirective onUpstreamFailure(Throwable cause, Context<IncomingConnection> ctx) {
// signal the failure to external monitoring service!
return super.onUpstreamFailure(cause, ctx);
}
});
Future<ServerBinding> serverBindingFuture =
serverSource
.via(failureDetection) // feed signals through our custom stage
.to(Sink.foreach(
new Procedure<IncomingConnection>() {
@Override
public void apply(IncomingConnection connection) throws Exception {
System.out.println("Accepted new connection from " + connection.remoteAddress());
// ... and then actually handle the connection
}
})).run(materializer);
//#incoming-connections-source-failure-handling
Await.result(serverBindingFuture, new FiniteDuration(3, TimeUnit.SECONDS));
}
public static void connectionStreamFailureExample() throws Exception {
//#connection-stream-failure-handling
ActorSystem system = ActorSystem.create();
Materializer materializer = ActorMaterializer.create(system);
Source<IncomingConnection, Future<ServerBinding>> serverSource =
Http.get(system).bind("localhost", 8080, materializer);
Flow<HttpRequest, HttpRequest, BoxedUnit> failureDetection =
Flow.of(HttpRequest.class).transform(() ->
new PushStage<HttpRequest, HttpRequest>() {
@Override
public SyncDirective onPush(HttpRequest elem, Context<HttpRequest> ctx) {
return ctx.push(elem);
}
@Override
public TerminationDirective onUpstreamFailure(Throwable cause, Context<HttpRequest> ctx) {
// signal the failure to external monitoring service!
return super.onUpstreamFailure(cause, ctx);
}
});
Flow<HttpRequest, HttpResponse, BoxedUnit> httpEcho =
Flow.of(HttpRequest.class)
.via(failureDetection)
.map(request -> {
Source<ByteString, ?> bytes = request.entity().getDataBytes();
HttpEntity entity = HttpEntities.create(ContentTypes.TEXT_PLAIN, (Source<ByteString, Object>) bytes);
return HttpResponse.create()
.withEntity(entity);
});
Future<ServerBinding> serverBindingFuture =
serverSource.to(Sink.foreach(con -> {
System.out.println("Accepted new connection from " + con.remoteAddress());
con.handleWith(httpEcho, materializer);
}
)).run(materializer);
//#connection-stream-failure-handling
Await.result(serverBindingFuture, new FiniteDuration(3, TimeUnit.SECONDS));
}
public static void fullServerExample() throws Exception {
//#full-server-example
ActorSystem system = ActorSystem.create();

View file

@ -42,11 +42,11 @@ HttpRequest
An ``HttpRequest`` consists of
- a method (GET, POST, etc.)
- a URI
- a seq of headers
- an entity (body data)
- a protocol
- a method (GET, POST, etc.)
- a URI
- a seq of headers
- an entity (body data)
- a protocol
Here are some examples how to construct an ``HttpRequest``:
@ -64,10 +64,10 @@ HttpResponse
An ``HttpResponse`` consists of
- a status code
- a list of headers
- an entity (body data)
- a protocol
- a status code
- a list of headers
- an entity (body data)
- a protocol
Here are some examples how to construct an ``HttpResponse``:

View file

@ -31,11 +31,11 @@ akka-http-jackson
.. toctree::
:maxdepth: 2
configuration
http-model
server-side/low-level-server-side-api
server-side/websocket-support
routing-dsl/index
client-side/index
configuration
.. _jackson: https://github.com/FasterXML/jackson

View file

@ -6,10 +6,10 @@ Directives
A directive is a wrapper for a route or a list of alternative routes that adds one or more of the following
functionality to its nested route(s):
* it filters the request and lets only matching requests pass (e.g. the `get` directive lets only GET-requests pass)
* it modifies the request or the ``RequestContext`` (e.g. the `path` directives filters on the unmatched path and then
passes an updated ``RequestContext`` unmatched path)
* it modifies the response coming out of the nested route
* it filters the request and lets only matching requests pass (e.g. the `get` directive lets only GET-requests pass)
* it modifies the request or the ``RequestContext`` (e.g. the `path` directives filters on the unmatched path and then
passes an updated ``RequestContext`` unmatched path)
* it modifies the response coming out of the nested route
akka-http provides a set of predefined directives for various tasks. You can access them by either extending from
``akka.http.javadsl.server.AllDirectives`` or by importing them statically with
@ -46,7 +46,7 @@ MethodDirectives
MiscDirectives
Contains directives that validate a request by user-defined logic.
:ref:`PathDirectives-java`
:ref:`path-directives-java`
Contains directives to match and filter on the URI path of the incoming request.
RangeDirectives

View file

@ -1,4 +1,4 @@
.. _PathDirectives-java:
.. _path-directives-java:
PathDirectives
==============

View file

@ -74,3 +74,27 @@ quickly without running them over the network and helps with writing assertions
Read more about :ref:`http-testkit-java`.
.. _DRY: http://en.wikipedia.org/wiki/Don%27t_repeat_yourself
.. _handling-http-server-failures-high-level-scala:
Handling HTTP Server failures in the High-Level API
---------------------------------------------------
There are various situations when failure may occur while initialising or running an Akka HTTP server.
Akka by default will log all these failures, however sometimes one may want to react to failures in addition
to them just being logged, for example by shutting down the actor system, or notifying some external monitoring
end-point explicitly.
Bind failures
^^^^^^^^^^^^^
For example the server might be unable to bind to the given port. For example when the port
is already taken by another application, or if the port is privileged (i.e. only usable by ``root``).
In this case the "binding future" will fail immediatly, and we can react to if by listening on the Future's completion:
.. includecode:: ../../code/docs/http/javadsl/server/HighLevelServerBindFailureExample.java
:include: binding-failure-high-level-example
.. note::
For a more low-level overview of the kinds of failures that can happen and also more fine-grained control over them
refer to the :ref:`handling-http-server-failures-low-level-java` documentation.

View file

@ -93,9 +93,9 @@ this connection.
Requests are handled by calling one of the ``handleWithXXX`` methods with a handler, which can either be
- a ``Flow<HttpRequest, HttpResponse, ?>`` for ``handleWith``,
- a function ``Function<HttpRequest, HttpResponse>`` for ``handleWithSyncHandler``,
- a function ``Function<HttpRequest, Future<HttpResponse>>`` for ``handleWithAsyncHandler``.
- a ``Flow<HttpRequest, HttpResponse, ?>`` for ``handleWith``,
- a function ``Function<HttpRequest, HttpResponse>`` for ``handleWithSyncHandler``,
- a function ``Function<HttpRequest, Future<HttpResponse>>`` for ``handleWithAsyncHandler``.
Here is a complete example:
@ -165,4 +165,64 @@ that is a stage that "upgrades" a potentially encrypted raw connection to the HT
You create an instance of the layer by calling one of the two overloads of the ``Http.get(system).serverLayer`` method,
which also allows for varying degrees of configuration. Note, that the returned instance is not reusable and can only
be materialized once.
be materialized once.
.. _handling-http-server-failures-low-level-java:
Handling HTTP Server failures in the Low-Level API
--------------------------------------------------
There are various situations when failure may occur while initialising or running an Akka HTTP server.
Akka by default will log all these failures, however sometimes one may want to react to failures in addition to them
just being logged, for example by shutting down the actor system, or notifying some external monitoring end-point explicitly.
There are multiple things that can fail when creating and materializing an HTTP Server (similarily, the same applied to
a plain streaming ``Tcp`` server). The types of failures that can happen on different layers of the stack, starting
from being unable to start the server, and ending with failing to unmarshal an HttpRequest, examples of failures include
(from outer-most, to inner-most):
- Failure to ``bind`` to the specified address/port,
- Failure while accepting new ``IncommingConnection`` s, for example when the OS has run out of file descriptors or memory,
- Failure while handling a connection, for example if the incoming ``HttpRequest`` is malformed.
This section describes how to handle each failure situation, and in which situations these failures may occur.
Bind failures
^^^^^^^^^^^^^
The first type of failure is when the server is unable to bind to the given port. For example when the port
is already taken by another application, or if the port is privileged (i.e. only usable by ``root``).
In this case the "binding future" will fail immediatly, and we can react to if by listening on the Future's completion:
.. includecode:: ../../code/docs/http/javadsl/server/HttpServerExampleDocTest.java
:include: binding-failure-handling
Once the server has successfully bound to a port, the ``Source<IncomingConnection, ?>`` starts running and emiting
new incoming connections. This source technically can signal a failure as well, however this should only happen in very
dramantic situations such as running out of file descriptors or memory available to the system, such that it's not able
to accept a new incoming connection. Handling failures in Akka Streams is pretty stright forward, as failures are signaled
through the stream starting from the stage which failed, all the way downstream to the final stages.
Connections Source failures
^^^^^^^^^^^^^^^^^^^^^^^^^^^
In the example below we add a custom ``PushStage`` (see :ref:`stream-customize-java`) in order to react to the
stream's failure. We signal a ``failureMonitor`` actor with the cause why the stream is going down, and let the Actor
handle the rest maybe it'll decide to restart the server or shutdown the ActorSystem, that however is not our concern anymore.
.. includecode:: ../../code/docs/http/javadsl/server/HttpServerExampleDocTest.java
:include: incoming-connections-source-failure-handling
Connection failures
^^^^^^^^^^^^^^^^^^^
The third type of failure that can occur is when the connection has been properly established,
however afterwards is terminated abruptly for example by the client aborting the underlying TCP connection.
To handle this failure we can use the same pattern as in the previous snippet, however apply it to the connection's Flow:
.. includecode:: ../../code/docs/http/javadsl/server/HttpServerExampleDocTest.java
:include: connection-stream-failure-handling
These failures can be described more or less infrastructure related, they are failing bindings or connections.
Most of the time you won't need to dive into those very deeply, as Akka will simply log errors of this kind
anyway, which is a reasonable default for such problems.

View file

@ -4,7 +4,7 @@ Scala Documentation
===================
.. toctree::
:maxdepth: 2
:maxdepth: 3
scala/stream-index
scala/http/index

View file

@ -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 = ???
}
}
*/

View file

@ -3,19 +3,15 @@
*/
package docs.stream.io
import java.net.InetSocketAddress
import java.util.concurrent.atomic.AtomicReference
import akka.stream._
import akka.stream.scaladsl.Tcp._
import akka.stream.scaladsl._
import akka.stream.stage.Context
import akka.stream.stage.PushStage
import akka.stream.stage.SyncDirective
import akka.stream.stage.{ Context, PushStage, SyncDirective }
import akka.stream.testkit.AkkaSpec
import akka.testkit.TestProbe
import akka.util.ByteString
import docs.stream.cookbook.RecipeParseLines
import docs.utils.TestUtils
import scala.concurrent.Future
@ -31,8 +27,14 @@ class StreamTcpDocSpec extends AkkaSpec {
"simple server connection" in {
{
//#echo-server-simple-bind
val connections: Source[IncomingConnection, Future[ServerBinding]] =
Tcp().bind("127.0.0.1", 8888)
val binding: Future[ServerBinding] =
Tcp().bind("127.0.0.1", 8888).to(Sink.ignore).run()
binding.map { b =>
b.unbind() onComplete {
case _ => // ...
}
}
//#echo-server-simple-bind
}
{

View file

@ -167,4 +167,68 @@ On the server-side the stand-alone HTTP layer forms a ``BidiFlow`` that is defin
:snippet: server-layer
You create an instance of ``Http.ServerLayer`` by calling one of the two overloads of the ``Http().serverLayer`` method,
which also allows for varying degrees of configuration.
which also allows for varying degrees of configuration.
.. _handling-http-server-failures-low-level-scala:
Handling HTTP Server failures in the Low-Level API
--------------------------------------------------
There are various situations when failure may occur while initialising or running an Akka HTTP server.
Akka by default will log all these failures, however sometimes one may want to react to failures in addition to them
just being logged, for example by shutting down the actor system, or notifying some external monitoring end-point explicitly.
There are multiple things that can fail when creating and materializing an HTTP Server (similarily, the same applied to
a plain streaming ``Tcp()`` server). The types of failures that can happen on different layers of the stack, starting
from being unable to start the server, and ending with failing to unmarshal an HttpRequest, examples of failures include
(from outer-most, to inner-most):
- Failure to ``bind`` to the specified address/port,
- Failure while accepting new ``IncommingConnection`` s, for example when the OS has run out of file descriptors or memory,
- Failure while handling a connection, for example if the incoming ``HttpRequest`` is malformed.
This section describes how to handle each failure situation, and in which situations these failures may occur.
Bind failures
^^^^^^^^^^^^^
The first type of failure is when the server is unable to bind to the given port. For example when the port
is already taken by another application, or if the port is privileged (i.e. only usable by ``root``).
In this case the "binding future" will fail immediatly, and we can react to if by listening on the Future's completion:
.. includecode2:: ../code/docs/http/scaladsl/HttpServerExampleSpec.scala
:snippet: binding-failure-handling
Once the server has successfully bound to a port, the ``Source[IncomingConnection, _]`` starts running and emiting
new incoming connections. This source technically can signal a failure as well, however this should only happen in very
dramantic situations such as running out of file descriptors or memory available to the system, such that it's not able
to accept a new incoming connection. Handling failures in Akka Streams is pretty stright forward, as failures are signaled
through the stream starting from the stage which failed, all the way downstream to the final stages.
Connections Source failures
^^^^^^^^^^^^^^^^^^^^^^^^^^^
In the example below we add a custom ``PushStage`` (see :ref:`stream-customize-scala`) in order to react to the
stream's failure. We signal a ``failureMonitor`` actor with the cause why the stream is going down, and let the Actor
handle the rest maybe it'll decide to restart the server or shutdown the ActorSystem, that however is not our concern anymore.
.. includecode2:: ../code/docs/http/scaladsl/HttpServerExampleSpec.scala
:snippet: incoming-connections-source-failure-handling
Connection failures
^^^^^^^^^^^^^^^^^^^
The third type of failure that can occur is when the connection has been properly established,
however afterwards is terminated abruptly for example by the client aborting the underlying TCP connection.
To handle this failure we can use the same pattern as in the previous snippet, however apply it to the connection's Flow:
.. includecode2:: ../code/docs/http/scaladsl/HttpServerExampleSpec.scala
:snippet: connection-stream-failure-handling
These failures can be described more or less infrastructure related, they are failing bindings or connections.
Most of the time you won't need to dive into those very deeply, as Akka will simply log errors of this kind
anyway, which is a reasonable default for such problems.
In order to learn more about handling exceptions in the actual routing layer, which is where your application code
comes into the picture, refer to :ref:`exception-handling-scala` which focuses explicitly on explaining how exceptions
thrown in routes can be handled and transformed into :class:`HttpResponse` s with apropriate error codes and human-readable failure descriptions.

View file

@ -17,7 +17,7 @@ Description
Using this directive is an alternative to using a global implicitly defined ``ExceptionHandler`` that
applies to the complete route.
See :ref:`Exception Handling` for general information about options for handling exceptions.
See :ref:`exception-handling-scala` for general information about options for handling exceptions.
Example
-------

View file

@ -4,7 +4,7 @@ failWith
========
Bubbles up the given error through the route structure where it is dealt with by the closest ``handleExceptions``
directive and its ``ExceptionHandler``.
directive and its :class:`ExceptionHandler`.
Signature
@ -19,12 +19,12 @@ Description
``failWith`` explicitly raises an exception that gets bubbled up through the route structure to be picked up by the
nearest ``handleExceptions`` directive. Using ``failWith`` rather than simply throwing an exception enables the route
structure's :ref:`Exception Handling` mechanism to deal with the exception even if the current route is executed
structure's :ref:`exception-handling-scala` mechanism to deal with the exception even if the current route is executed
asynchronously on another thread (e.g. in a ``Future`` or separate actor).
If no ``handleExceptions`` is present above the respective location in the
route structure the top-level routing logic will handle the exception and translate it into a corresponding
``HttpResponse`` using the in-scope ``ExceptionHandler`` (see also the :ref:`Exception Handling` chapter).
``HttpResponse`` using the in-scope ``ExceptionHandler`` (see also the :ref:`exception-handling-scala` chapter).
There is one notable special case: If the given exception is a ``RejectionError`` exception it is *not* bubbled up,
but rather the wrapped exception is unpacked and "executed". This allows the "tunneling" of a rejection via an

View file

@ -1,4 +1,4 @@
.. _Exception Handling:
.. _exception-handling-scala:
Exception Handling
==================

View file

@ -43,4 +43,34 @@ not really do anything useful but its definition should give you a feel for what
the Routing DSL will look like:
.. includecode2:: ../../code/docs/http/scaladsl/HttpServerExampleSpec.scala
:snippet: long-routing-example
:snippet: long-routing-example
.. _handling-http-server-failures-high-level-scala:
Handling HTTP Server failures in the High-Level API
---------------------------------------------------
There are various situations when failure may occur while initialising or running an Akka HTTP server.
Akka by default will log all these failures, however sometimes one may want to react to failures in addition
to them just being logged, for example by shutting down the actor system, or notifying some external monitoring
end-point explicitly.
Bind failures
^^^^^^^^^^^^^
For example the server might be unable to bind to the given port. For example when the port
is already taken by another application, or if the port is privileged (i.e. only usable by ``root``).
In this case the "binding future" will fail immediatly, and we can react to if by listening on the Future's completion:
.. includecode2:: ../../code/docs/http/scaladsl/HttpServerExampleSpec.scala
:snippet: binding-failure-high-level-example
.. note::
For a more low-level overview of the kinds of failures that can happen and also more fine-grained control over them
refer to the :ref:`handling-http-server-failures-low-level-scala` documentation.
Failures and exceptions inside the Routing DSL
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Exception handling within the Routing DSL is done by providing :class:`ExceptionHandler` s which are documented in-depth
in the :ref:`exception-handling-scala` section of the documtnation. You can use them to transform exceptions into
:class:`HttpResponse` s with apropriate error codes and human-readable failure descriptions.

View file

@ -14,7 +14,7 @@ Generally when a route receives a request (or rather a ``RequestContext`` for it
- Complete the request by returning the value of ``requestContext.complete(...)``
- Reject the request by returning the value of ``requestContext.reject(...)`` (see :ref:`Rejections`)
- Fail the request by returning the value of ``requestContext.fail(...)`` or by just throwing an exception (see :ref:`Exception Handling`)
- Fail the request by returning the value of ``requestContext.fail(...)`` or by just throwing an exception (see :ref:`exception-handling-scala`)
- Do any kind of asynchronous processing and instantly return a ``Future[RouteResult]`` to be eventually completed later
The first case is pretty clear, by calling ``complete`` a given response is sent to the client as reaction to the

View file

@ -7,8 +7,8 @@ package akka.http.javadsl.model;
import java.io.File;
import akka.http.impl.util.JavaAccessors;
import akka.http.scaladsl.model.*;
import akka.http.scaladsl.model.HttpEntity;
import akka.http.scaladsl.model.HttpEntity$;
import akka.util.ByteString;
import akka.stream.javadsl.Source;

View file

@ -5,6 +5,7 @@
package akka.http.javadsl.model;
import akka.japi.Option;
import akka.stream.javadsl.Source;
import akka.util.ByteString;
import java.io.File;