Utilise Reactor Netty's new graceful shutdown support

Closes gh-20613
This commit is contained in:
Andy Wilkinson 2020-03-23 10:51:55 +00:00
parent 6b47dd06e8
commit 4cdb968efa
2 changed files with 16 additions and 49 deletions

View File

@ -17,19 +17,13 @@
package org.springframework.boot.web.embedded.netty;
import java.time.Duration;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Publisher;
import reactor.netty.DisposableServer;
import reactor.netty.http.server.HttpServerRequest;
import reactor.netty.http.server.HttpServerResponse;
import org.springframework.boot.web.server.GracefulShutdown;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
/**
* {@link GracefulShutdown} for a Reactor Netty {@link DisposableServer}.
@ -42,17 +36,12 @@ final class NettyGracefulShutdown implements GracefulShutdown {
private final Supplier<DisposableServer> disposableServer;
private final Duration lifecycleTimeout;
private final Duration period;
private final AtomicLong activeRequests = new AtomicLong();
private volatile boolean shuttingDown;
NettyGracefulShutdown(Supplier<DisposableServer> disposableServer, Duration lifecycleTimeout, Duration period) {
NettyGracefulShutdown(Supplier<DisposableServer> disposableServer, Duration period) {
this.disposableServer = disposableServer;
this.lifecycleTimeout = lifecycleTimeout;
this.period = period;
}
@ -64,32 +53,19 @@ final class NettyGracefulShutdown implements GracefulShutdown {
if (server == null) {
return false;
}
if (this.lifecycleTimeout != null) {
server.disposeNow(this.lifecycleTimeout);
}
else {
server.disposeNow();
}
this.shuttingDown = true;
long end = System.currentTimeMillis() + this.period.toMillis();
try {
while (this.activeRequests.get() > 0 && System.currentTimeMillis() < end) {
try {
Thread.sleep(50);
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
break;
}
if (this.period != null) {
server.disposeNow(this.period);
}
long activeRequests = this.activeRequests.get();
if (activeRequests == 0) {
logger.info("Graceful shutdown complete");
return true;
}
if (logger.isInfoEnabled()) {
logger.info("Grace period elapsed with " + activeRequests + " request(s) still active");
else {
server.disposeNow();
}
logger.info("Graceful shutdown complete");
return true;
}
catch (IllegalStateException ex) {
logger.info("Grace period elapsed with one ore more requests still active");
return false;
}
finally {
@ -102,15 +78,4 @@ final class NettyGracefulShutdown implements GracefulShutdown {
return this.shuttingDown;
}
BiFunction<? super HttpServerRequest, ? super HttpServerResponse, ? extends Publisher<Void>> wrapHandler(
ReactorHttpHandlerAdapter handlerAdapter) {
if (this.period == null) {
return handlerAdapter;
}
return (request, response) -> {
this.activeRequests.incrementAndGet();
return handlerAdapter.apply(request, response).doOnTerminate(() -> this.activeRequests.decrementAndGet());
};
}
}

View File

@ -22,6 +22,8 @@ import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.DefaultEventExecutor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Publisher;
@ -84,16 +86,16 @@ public class NettyWebServer implements WebServer {
Duration shutdownGracePeriod) {
Assert.notNull(httpServer, "HttpServer must not be null");
Assert.notNull(handlerAdapter, "HandlerAdapter must not be null");
this.httpServer = httpServer;
this.lifecycleTimeout = lifecycleTimeout;
this.handler = handlerAdapter;
if (shutdownGracePeriod != null) {
this.httpServer = httpServer.channelGroup(new DefaultChannelGroup(new DefaultEventExecutor()));
NettyGracefulShutdown gracefulShutdown = new NettyGracefulShutdown(() -> this.disposableServer,
lifecycleTimeout, shutdownGracePeriod);
this.handler = gracefulShutdown.wrapHandler(handlerAdapter);
shutdownGracePeriod);
this.shutdown = gracefulShutdown;
}
else {
this.handler = handlerAdapter;
this.httpServer = httpServer;
this.shutdown = new ImmediateGracefulShutdown();
}
}