Skip to content

Commit 95a8f47

Browse files
committed
Merge #2758 into 1.1.6
2 parents 70e7216 + c1b9631 commit 95a8f47

File tree

2 files changed

+46
-13
lines changed

2 files changed

+46
-13
lines changed

reactor-netty-core/src/main/java/reactor/netty/transport/ServerTransport.java

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import reactor.netty.Connection;
5151
import reactor.netty.ConnectionObserver;
5252
import reactor.netty.DisposableServer;
53+
import reactor.netty.FutureMono;
5354
import reactor.netty.channel.AbortedException;
5455
import reactor.netty.channel.ChannelOperations;
5556
import reactor.netty.internal.util.MapUtils;
@@ -530,12 +531,15 @@ public final void dispose() {
530531
@Override
531532
@SuppressWarnings("FutureReturnValueIgnored")
532533
public void disposeNow(Duration timeout) {
533-
if (log.isDebugEnabled()) {
534-
log.debug(format(channel(), "Server is about to be disposed with timeout: {}"), timeout);
535-
}
536534
if (isDisposed()) {
535+
if (log.isDebugEnabled()) {
536+
log.debug(format(channel(), "Server has been disposed"));
537+
}
537538
return;
538539
}
540+
if (log.isDebugEnabled()) {
541+
log.debug(format(channel(), "Server is about to be disposed with timeout: {}"), timeout);
542+
}
539543
dispose();
540544
Mono<Void> terminateSignals = Mono.empty();
541545
if (config.channelGroup != null && config.channelGroup.size() > 0) {
@@ -544,10 +548,21 @@ public void disposeNow(Duration timeout) {
544548
// Wait for the running requests to finish
545549
for (Channel channel : config.channelGroup) {
546550
Channel parent = channel.parent();
551+
// For TCP and HTTP/1.1 the channel parent is the ServerChannel
552+
boolean isParentServerChannel = parent instanceof ServerChannel;
547553
List<Mono<Void>> monos =
548554
MapUtils.computeIfAbsent(channelsToMono,
549-
parent instanceof ServerChannel ? channel : parent,
550-
key -> new ArrayList<>());
555+
isParentServerChannel ? channel : parent,
556+
key -> {
557+
List<Mono<Void>> list = new ArrayList<>();
558+
if (!isParentServerChannel) {
559+
// In case of HTTP/2 Reactor Netty will send GO_AWAY with lastStreamId to notify the
560+
// client to stop opening streams, the actual CLOSE will happen when all
561+
// streams up to lastStreamId are closed
562+
list.add(FutureMono.from(key.close()));
563+
}
564+
return list;
565+
});
551566
ChannelOperations<?, ?> ops = ChannelOperations.get(channel);
552567
if (ops != null) {
553568
monos.add(ops.onTerminate().doFinally(sig -> ops.dispose()));
@@ -558,16 +573,12 @@ public void disposeNow(Duration timeout) {
558573
List<Mono<Void>> monos = entry.getValue();
559574
if (monos.isEmpty()) {
560575
// At this point there are no running requests for this channel
576+
// This can happen for TCP and HTTP/1.1
561577
// "FutureReturnValueIgnored" this is deliberate
562578
channel.close();
563579
}
564580
else {
565-
terminateSignals =
566-
Mono.when(monos)
567-
// At this point there are no running requests for this channel
568-
// "FutureReturnValueIgnored" this is deliberate
569-
.doFinally(sig -> channel.close())
570-
.and(terminateSignals);
581+
terminateSignals = Mono.when(monos).and(terminateSignals);
571582
}
572583
}
573584
}

reactor-netty-http/src/main/java/reactor/netty/http/server/HttpServerConfig.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ static void configureH2Pipeline(ChannelPipeline p,
519519
@Nullable BiPredicate<HttpServerRequest, HttpServerResponse> compressPredicate,
520520
ServerCookieDecoder cookieDecoder,
521521
ServerCookieEncoder cookieEncoder,
522+
boolean enableGracefulShutdown,
522523
HttpServerFormDecoderProvider formDecoderProvider,
523524
@Nullable BiFunction<ConnectionInfo, HttpRequest, ConnectionInfo> forwardedHeaderHandler,
524525
Http2Settings http2Settings,
@@ -538,6 +539,12 @@ static void configureH2Pipeline(ChannelPipeline p,
538539
.validateHeaders(validate)
539540
.initialSettings(http2Settings);
540541

542+
if (enableGracefulShutdown) {
543+
// Configure the graceful shutdown with indefinite timeout as Reactor Netty controls the timeout
544+
// when disposeNow(timeout) is invoked
545+
http2FrameCodecBuilder.gracefulShutdownTimeoutMillis(-1);
546+
}
547+
541548
if (p.get(NettyPipeline.LoggingHandler) != null) {
542549
http2FrameCodecBuilder.frameLogger(new Http2FrameLogger(LogLevel.DEBUG,
543550
"reactor.netty.http.server.h2"));
@@ -569,6 +576,7 @@ static void configureHttp11OrH2CleartextPipeline(ChannelPipeline p,
569576
ServerCookieDecoder cookieDecoder,
570577
ServerCookieEncoder cookieEncoder,
571578
HttpRequestDecoderSpec decoder,
579+
boolean enableGracefulShutdown,
572580
HttpServerFormDecoderProvider formDecoderProvider,
573581
@Nullable BiFunction<ConnectionInfo, HttpRequest, ConnectionInfo> forwardedHeaderHandler,
574582
Http2Settings http2Settings,
@@ -587,7 +595,7 @@ static void configureHttp11OrH2CleartextPipeline(ChannelPipeline p,
587595
decoder.allowDuplicateContentLengths());
588596

589597
Http11OrH2CleartextCodec upgrader = new Http11OrH2CleartextCodec(accessLogEnabled, accessLog, compressPredicate,
590-
cookieDecoder, cookieEncoder, p.get(NettyPipeline.LoggingHandler) != null, formDecoderProvider,
598+
cookieDecoder, cookieEncoder, p.get(NettyPipeline.LoggingHandler) != null, enableGracefulShutdown, formDecoderProvider,
591599
forwardedHeaderHandler, http2Settings, httpMessageLogFactory, listener, mapHandle, metricsRecorder,
592600
minCompressionSize, opsFactory, uriTagValue, decoder.validateHeaders());
593601

@@ -912,6 +920,7 @@ static final class Http11OrH2CleartextCodec extends ChannelInitializer<Channel>
912920
ServerCookieDecoder cookieDecoder,
913921
ServerCookieEncoder cookieEncoder,
914922
boolean debug,
923+
boolean enableGracefulShutdown,
915924
HttpServerFormDecoderProvider formDecoderProvider,
916925
@Nullable BiFunction<ConnectionInfo, HttpRequest, ConnectionInfo> forwardedHeaderHandler,
917926
Http2Settings http2Settings,
@@ -935,6 +944,12 @@ static final class Http11OrH2CleartextCodec extends ChannelInitializer<Channel>
935944
.validateHeaders(validate)
936945
.initialSettings(http2Settings);
937946

947+
if (enableGracefulShutdown) {
948+
// Configure the graceful shutdown with indefinite timeout as Reactor Netty controls the timeout
949+
// when disposeNow(timeout) is invoked
950+
http2FrameCodecBuilder.gracefulShutdownTimeoutMillis(-1);
951+
}
952+
938953
if (debug) {
939954
http2FrameCodecBuilder.frameLogger(new Http2FrameLogger(
940955
LogLevel.DEBUG,
@@ -981,6 +996,7 @@ static final class H2OrHttp11Codec extends ApplicationProtocolNegotiationHandler
981996
final ServerCookieDecoder cookieDecoder;
982997
final ServerCookieEncoder cookieEncoder;
983998
final HttpRequestDecoderSpec decoder;
999+
final boolean enableGracefulShutdown;
9841000
final HttpServerFormDecoderProvider formDecoderProvider;
9851001
final BiFunction<ConnectionInfo, HttpRequest, ConnectionInfo> forwardedHeaderHandler;
9861002
final Http2Settings http2Settings;
@@ -1003,6 +1019,7 @@ static final class H2OrHttp11Codec extends ApplicationProtocolNegotiationHandler
10031019
this.cookieDecoder = initializer.cookieDecoder;
10041020
this.cookieEncoder = initializer.cookieEncoder;
10051021
this.decoder = initializer.decoder;
1022+
this.enableGracefulShutdown = initializer.enableGracefulShutdown;
10061023
this.formDecoderProvider = initializer.formDecoderProvider;
10071024
this.forwardedHeaderHandler = initializer.forwardedHeaderHandler;
10081025
this.http2Settings = initializer.http2Settings;
@@ -1027,7 +1044,7 @@ protected void configurePipeline(ChannelHandlerContext ctx, String protocol) {
10271044

10281045
if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
10291046
configureH2Pipeline(p, accessLogEnabled, accessLog, compressPredicate, cookieDecoder, cookieEncoder,
1030-
formDecoderProvider, forwardedHeaderHandler, http2Settings, httpMessageLogFactory, idleTimeout,
1047+
enableGracefulShutdown, formDecoderProvider, forwardedHeaderHandler, http2Settings, httpMessageLogFactory, idleTimeout,
10311048
listener, mapHandle, metricsRecorder, minCompressionSize, opsFactory, uriTagValue, decoder.validateHeaders());
10321049
return;
10331050
}
@@ -1056,6 +1073,7 @@ static final class HttpServerChannelInitializer implements ChannelPipelineConfig
10561073
final ServerCookieDecoder cookieDecoder;
10571074
final ServerCookieEncoder cookieEncoder;
10581075
final HttpRequestDecoderSpec decoder;
1076+
final boolean enableGracefulShutdown;
10591077
final HttpServerFormDecoderProvider formDecoderProvider;
10601078
final BiFunction<ConnectionInfo, HttpRequest, ConnectionInfo> forwardedHeaderHandler;
10611079
final Http2Settings http2Settings;
@@ -1080,6 +1098,7 @@ static final class HttpServerChannelInitializer implements ChannelPipelineConfig
10801098
this.cookieDecoder = config.cookieDecoder;
10811099
this.cookieEncoder = config.cookieEncoder;
10821100
this.decoder = config.decoder;
1101+
this.enableGracefulShutdown = config.channelGroup() != null;
10831102
this.formDecoderProvider = config.formDecoderProvider;
10841103
this.forwardedHeaderHandler = config.forwardedHeaderHandler;
10851104
this.http2Settings = config.http2Settings();
@@ -1147,6 +1166,7 @@ else if ((protocols & h2) == h2) {
11471166
compressPredicate(compressPredicate, minCompressionSize),
11481167
cookieDecoder,
11491168
cookieEncoder,
1169+
enableGracefulShutdown,
11501170
formDecoderProvider,
11511171
forwardedHeaderHandler,
11521172
http2Settings,
@@ -1171,6 +1191,7 @@ else if ((protocols & h2) == h2) {
11711191
cookieDecoder,
11721192
cookieEncoder,
11731193
decoder,
1194+
enableGracefulShutdown,
11741195
formDecoderProvider,
11751196
forwardedHeaderHandler,
11761197
http2Settings,
@@ -1212,6 +1233,7 @@ else if ((protocols & h2c) == h2c) {
12121233
compressPredicate(compressPredicate, minCompressionSize),
12131234
cookieDecoder,
12141235
cookieEncoder,
1236+
enableGracefulShutdown,
12151237
formDecoderProvider,
12161238
forwardedHeaderHandler,
12171239
http2Settings,

0 commit comments

Comments
 (0)