Skip to content

Commit

Permalink
Rewrite the TCP/HTTP close section and added missing shutdown section.
Browse files Browse the repository at this point in the history
  • Loading branch information
vietj committed Nov 16, 2024
1 parent c942a76 commit f5437e0
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 31 deletions.
40 changes: 40 additions & 0 deletions vertx-core/src/main/asciidoc/http.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1869,6 +1869,46 @@ Connection {@link io.vertx.core.http.HttpConnection#close} closes the connection

The {@link io.vertx.core.http.HttpConnection#closeHandler} notifies when a connection is closed.

=== Graceful shutdown

HTTP server and client support graceful shutdown.

You can shut down a {@link io.vertx.core.http.HttpServer#shutdown() server} or {@link io.vertx.core.http.HttpClient#shutdown() client}.

Calling `shutdown` initiates the shut-down phase whereby the server or client are given the opportunity to perform clean-up actions.

- A standalone HTTP server unbinds
- A shared HTTP server is removed from the set of accepting servers
- An HTTP client refuses to send any new requests

When all connections inflight requests are processed, the server or client is then closed.

In addition, HTTP/2 connections send a `GOAWAY` frame to signal the remote endpoint that the connection cannot be used anymore.

[source,$lang]
----
{@link examples.HTTPExamples#serverShutdown}
----

Shut-down waits until all sockets are closed or the shut-down timeout fires. When the timeout fires, all sockets are
forcibly closed.

Each opened HTTP connections is notified with a shutdown event, allowing to perform cleanup before the
actual connection is closed.

[source,$lang]
----
{@link examples.HTTPExamples#shutdownHandler}
----

The default shut-down timeout is 30 seconds, you can override the timeout

[source,$lang]
----
{@link examples.HTTPExamples#serverShutdownWithAmountOfTime}
----


=== Client sharing

You can share an HTTP client between multiple verticles or instances of the same verticle. Such client should be created outside
Expand Down
42 changes: 31 additions & 11 deletions vertx-core/src/main/asciidoc/net.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -177,31 +177,51 @@ A non SSL/TLS connection can be upgraded to SSL/TLS using {@link io.vertx.core.n
The server or client must be configured for SSL/TLS for this to work correctly. Please see the <<ssl, chapter on SSL/TLS>>
for more information.

=== Closing a TCP Server
=== TCP graceful shut down

Call {@link io.vertx.core.net.NetServer#close()} to close the server. Closing the server closes any open connections
and releases all server resources.
You can shut down a {@link io.vertx.core.net.NetServer#shutdown() server} or {@link io.vertx.core.net.NetClient#shutdown() client}.

The close is actually asynchronous and might not complete until some time after the call has returned.
If you want to be notified when the actual close has completed then you can pass in a handler.

This handler will then be called when the close has fully completed.
Calling `shutdown` initiates the shut-down phase whereby the server or client are given the opportunity to perform clean-up actions
and handle shutdown at the protocol level.

[source,$lang]
----
{@link examples.NetExamples#example9}
{@link examples.NetExamples#serverShutdown}
----

=== Client socket shutdown
Shut-down waits until all sockets are closed or the shut-down timeout fires. When the timeout fires, all sockets are
forcibly closed.

When a client is closed with a grace period, each socket opened by the client will be notified with a shutdown event, to
let the opportunity to perform a protocol level close before the actual socket close.
Each opened socket is notified with a shutdown event, allowing to perform a protocol level close before the
actual socket close.

[source,$lang]
----
{@link examples.NetExamples#shutdownHandler}
----

The default shut-down timeout is 30 seconds, you can override the amount of time

[source,$lang]
----
{@link examples.NetExamples#serverShutdownWithAmountOfTime}
----

=== TCP close

You can close a {@link io.vertx.core.net.NetServer#close() server} or {@link io.vertx.core.net.NetClient#close() client} to
immediately close all open connections and releases all resources. Unlike `shutdown` there is not grace period.

The close is actually asynchronous and might not complete until some time after the call has returned.
You can use the returned future to be notified when the actual close has completed.

This future is completed when the close has fully completed.

[source,$lang]
----
{@link examples.NetExamples#example9}
----

=== Automatic clean-up in verticles

If you're creating TCP servers and clients from inside verticles, those servers and clients will be automatically closed
Expand Down
35 changes: 35 additions & 0 deletions vertx-core/src/main/java/examples/HTTPExamples.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import io.vertx.core.file.OpenOptions;
import io.vertx.core.http.*;
import io.vertx.core.json.JsonObject;
import io.vertx.core.net.NetServer;
import io.vertx.core.net.endpoint.LoadBalancer;
import io.vertx.core.net.NetSocket;
import io.vertx.core.net.ProxyOptions;
Expand All @@ -29,6 +30,7 @@
import io.vertx.core.streams.ReadStream;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
* Created by tim on 09/01/15.
Expand Down Expand Up @@ -1359,6 +1361,39 @@ public static void compressorConfig() {
GzipOptions gzip = StandardCompressionOptions.gzip(6, 15, 8);
}

public void serverShutdown(HttpServer server) {
server
.shutdown()
.onSuccess(res -> {
System.out.println("Server is now closed");
});
}

public void serverShutdownWithAmountOfTime(HttpServer server) {
server
.shutdown(60, TimeUnit.SECONDS)
.onSuccess(res -> {
System.out.println("Server is now closed");
});
}

public void example9(HttpServer server) {

server
.close()
.onSuccess(res -> {
System.out.println("Server is now closed");
});
}

public void shutdownHandler(HttpServer server) {
server.connectionHandler(conn -> {
conn.shutdownHandler(v -> {
// Perform clean-up
});
});
}

public static void httpClientSharing1(Vertx vertx) {
HttpClientAgent client = vertx.createHttpClient(new HttpClientOptions().setShared(true));
vertx.deployVerticle(() -> new AbstractVerticle() {
Expand Down
56 changes: 36 additions & 20 deletions vertx-core/src/main/java/examples/NetExamples.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@
package examples;

import io.netty.handler.logging.ByteBufFormat;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.*;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.ClientAuth;
import io.vertx.core.http.HttpServer;
Expand Down Expand Up @@ -116,30 +113,49 @@ public void example8(NetSocket socket) {

}

public void serverShutdown(NetServer server) {
server
.shutdown()
.onSuccess(res -> {
System.out.println("Server is now closed");
});
}

public void serverShutdownWithAmountOfTime(NetServer server) {
server
.shutdown(60, TimeUnit.SECONDS)
.onSuccess(res -> {
System.out.println("Server is now closed");
});
}

public void example9(NetServer server) {

server
.close()
.onComplete(res -> {
if (res.succeeded()) {
System.out.println("Server is now closed");
} else {
System.out.println("close failed");
}
.onSuccess(res -> {
System.out.println("Server is now closed");
});
}

public void shutdownHandler(NetClient client, SocketAddress server) {
client
.connect(server)
.onSuccess(so -> {
so.shutdownHandler(timeout -> {
// Notified when the client is closing
});
});
private static Buffer closeFrame() {
return null;
}

private static Future<?> closeFrameHandler(NetSocket so) {
return null;
}

// A few moments later
client.shutdown(30, TimeUnit.SECONDS);
public void shutdownHandler(NetSocket socket) {
socket.shutdownHandler(v -> {
socket
// Write close frame
.write(closeFrame())
// Wait until we receive the remote close frame
.compose(success -> closeFrameHandler(socket))
// Close the socket
.eventually(() -> socket.close());
});
}

public void example9_1(NetSocket socket) {
Expand Down

0 comments on commit f5437e0

Please sign in to comment.