Skip to content

Commit

Permalink
Fixes #10484 - Clarify documentation about how to make a non-blocking… (
Browse files Browse the repository at this point in the history
#10934)

Added documentation about non-blocking Handlers.

Signed-off-by: Simone Bordet <[email protected]>
  • Loading branch information
sbordet authored Nov 30, 2023
1 parent 01b46aa commit 0ca80b9
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/http/HTTPSer
Such a simple `Handler` can access the request and response main features, such as xref:pg-server-http-handler-impl-request[reading request headers and content], or xref:pg-server-http-handler-impl-response[writing response headers and content].

Note how `HelloWorldHandler` extends from `Handler.Abstract.NonBlocking`.
This is a declaration that `HelloWorldHandler` does not use blocking APIs (of any kind) to perform its logic, allowing Jetty to apply optimizations that are not applied to ``Handler``s that declare themselves as blocking.
This is a declaration that `HelloWorldHandler` does not use blocking APIs (of any kind) to perform its logic, allowing Jetty to apply optimizations (see xref:pg-server-http-handler[here]) that are not applied to ``Handler``s that declare themselves as blocking.

If your `Handler` implementation uses blocking APIs (of any kind), extend from `Handler.Abstract`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,38 @@ Refer to xref:pg-server-http-handler-use[this section] for more information abou
You should write your own leaf ``Handler``s to implement your web application logic.
Refer to xref:pg-server-http-handler-impl[this section] for more information about how to write your own ``Handler``s.

// TODO: document ScopedHandler? Is this really necessary or just an implementation detail that application will never worry about?
A `Handler` may be declared as non-blocking (by extending `Handler.Abstract.NonBlocking`) or as blocking (by extending `Handler.Abstract`), to allow interaction with the xref:pg-arch-threads[Jetty threading architecture] for more efficient thread and CPU utilization during the request/response processing.

Container ``Handler``s typically inherit whether they are blocking or non-blocking from their child or children.

Furthermore, container ``Handler``s may be declared as dynamic: they allow adding/removing child ``Handler``s after they have been started (see link:{javadoc-url}/org/eclipse/jetty/server/Handler.AbstractContainer.html[Handler.AbstractContainer] for more information).
Dynamic container ``Handler``s are therefore always blocking, as it is not possible to know if a child `Handler` added in the future will be blocking or non-blocking.

If the `Handler` tree is not dynamic, then it is possible to create a non-blocking `Handler` tree, for example:

[source,screen]
----
Server
└── RewriteHandler
└── GzipHandler
└── ContextHandler
└── AppHandler extends Handler.Abstract.NonBlocking
----

When the `Handler` tree is non-blocking, Jetty may use the xref:pg-arch-threads-execution-strategy-pc[`Produce-Consume`] mode to invoke the `Handler` tree, therefore avoiding a thread hand-off, and saving the cost of being scheduled on a different CPU with cold caches.

The `Produce-Consume` mode is equivalent to what other servers call "event loop" or "selector thread loop" architectures.

This mode has the benefit of reducing OS context switches and CPU cache misses, using fewer threads, and it is overall very efficient.
On the other hand, it requires writing quick, non-blocking code, and partially sequentializes the request/response processing, so that the Nth request in the sequence pays the latency of the processing of the N-1 requests in front of it.

[IMPORTANT]
====
If you declare your `Handler` to be non-blocking by extending `Handler.Abstract.NonBlocking`, the code you write in `handle(\...)` (and recursively all the code called from there) must truly be non-blocking, and possibly execute quickly.
If the code blocks, you risk a server lock-up.
If the code takes a long time to execute, requests from other connections may be delayed.
====

include::server-http-handler-use.adoc[]
include::server-http-handler-implement.adoc[]

0 comments on commit 0ca80b9

Please sign in to comment.