Utilise Reactor Netty's new graceful shutdown support
Closes gh-20613
This commit is contained in:
parent
6b47dd06e8
commit
4cdb968efa
|
@ -17,19 +17,13 @@
|
||||||
package org.springframework.boot.web.embedded.netty;
|
package org.springframework.boot.web.embedded.netty;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.reactivestreams.Publisher;
|
|
||||||
import reactor.netty.DisposableServer;
|
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.boot.web.server.GracefulShutdown;
|
||||||
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link GracefulShutdown} for a Reactor Netty {@link DisposableServer}.
|
* {@link GracefulShutdown} for a Reactor Netty {@link DisposableServer}.
|
||||||
|
@ -42,17 +36,12 @@ final class NettyGracefulShutdown implements GracefulShutdown {
|
||||||
|
|
||||||
private final Supplier<DisposableServer> disposableServer;
|
private final Supplier<DisposableServer> disposableServer;
|
||||||
|
|
||||||
private final Duration lifecycleTimeout;
|
|
||||||
|
|
||||||
private final Duration period;
|
private final Duration period;
|
||||||
|
|
||||||
private final AtomicLong activeRequests = new AtomicLong();
|
|
||||||
|
|
||||||
private volatile boolean shuttingDown;
|
private volatile boolean shuttingDown;
|
||||||
|
|
||||||
NettyGracefulShutdown(Supplier<DisposableServer> disposableServer, Duration lifecycleTimeout, Duration period) {
|
NettyGracefulShutdown(Supplier<DisposableServer> disposableServer, Duration period) {
|
||||||
this.disposableServer = disposableServer;
|
this.disposableServer = disposableServer;
|
||||||
this.lifecycleTimeout = lifecycleTimeout;
|
|
||||||
this.period = period;
|
this.period = period;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,32 +53,19 @@ final class NettyGracefulShutdown implements GracefulShutdown {
|
||||||
if (server == null) {
|
if (server == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.lifecycleTimeout != null) {
|
this.shuttingDown = true;
|
||||||
server.disposeNow(this.lifecycleTimeout);
|
try {
|
||||||
|
if (this.period != null) {
|
||||||
|
server.disposeNow(this.period);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
server.disposeNow();
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
long activeRequests = this.activeRequests.get();
|
|
||||||
if (activeRequests == 0) {
|
|
||||||
logger.info("Graceful shutdown complete");
|
logger.info("Graceful shutdown complete");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (logger.isInfoEnabled()) {
|
catch (IllegalStateException ex) {
|
||||||
logger.info("Grace period elapsed with " + activeRequests + " request(s) still active");
|
logger.info("Grace period elapsed with one ore more requests still active");
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -102,15 +78,4 @@ final class NettyGracefulShutdown implements GracefulShutdown {
|
||||||
return this.shuttingDown;
|
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());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ import java.util.List;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Predicate;
|
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.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
|
@ -84,16 +86,16 @@ public class NettyWebServer implements WebServer {
|
||||||
Duration shutdownGracePeriod) {
|
Duration shutdownGracePeriod) {
|
||||||
Assert.notNull(httpServer, "HttpServer must not be null");
|
Assert.notNull(httpServer, "HttpServer must not be null");
|
||||||
Assert.notNull(handlerAdapter, "HandlerAdapter must not be null");
|
Assert.notNull(handlerAdapter, "HandlerAdapter must not be null");
|
||||||
this.httpServer = httpServer;
|
|
||||||
this.lifecycleTimeout = lifecycleTimeout;
|
this.lifecycleTimeout = lifecycleTimeout;
|
||||||
|
this.handler = handlerAdapter;
|
||||||
if (shutdownGracePeriod != null) {
|
if (shutdownGracePeriod != null) {
|
||||||
|
this.httpServer = httpServer.channelGroup(new DefaultChannelGroup(new DefaultEventExecutor()));
|
||||||
NettyGracefulShutdown gracefulShutdown = new NettyGracefulShutdown(() -> this.disposableServer,
|
NettyGracefulShutdown gracefulShutdown = new NettyGracefulShutdown(() -> this.disposableServer,
|
||||||
lifecycleTimeout, shutdownGracePeriod);
|
shutdownGracePeriod);
|
||||||
this.handler = gracefulShutdown.wrapHandler(handlerAdapter);
|
|
||||||
this.shutdown = gracefulShutdown;
|
this.shutdown = gracefulShutdown;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.handler = handlerAdapter;
|
this.httpServer = httpServer;
|
||||||
this.shutdown = new ImmediateGracefulShutdown();
|
this.shutdown = new ImmediateGracefulShutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue