apple / swift-nio-http2

HTTP/2 support for SwiftNIO
https://swiftpackageindex.com/apple/swift-nio-http2/main/documentation/niohttp2
Apache License 2.0
462 stars 82 forks source link

`NIOHTTP2Handler` should handle `ChannelShouldQuiesceEvent` #336

Open fabianfett opened 2 years ago

fabianfett commented 2 years ago

SwiftNIOExtras offers a QuiescingHelper to gracefully shutdown servers. NIOHTTP2Handler should support shutting down a server connection, when the QuiescingHelper sends out a ChannelShouldQuiesceEvent:

In NIOHTTP1 the ChannelShouldQuiesceEvent support is implemented in HTTPServerPipelineHandler

lmcd commented 2 years ago

Hmm maybe this is why I was having issues performing a soft-restart of a HTTP/2 Vapor server. I remember seeing quiesce/shutdown errors.

glbrntt commented 1 month ago
  • Once NIOHTTP2Handler receives a ChannelShouldQuiesceEvent a GoAway frame should be send to the client and new incoming streams should be rejected.
  • Once all previously open streams have finished the connection should be closed.

This needs to be handled carefully, the server should attempt to allow for 'in-flight' streams to be opened before it begins to reject streams. It can do this by sending a GOAWAY frame with lastStreamID set to .max followed immediately by a PING. On receiving the PING ACK – and thereby knowing the client received the previous GOAWAY frame – the server can send another GOAWAY frame with a lower lastStreamID, and then begin rejecting streams.

The client may for some reason not send a PING ACK which could leave the server waiting indefinitely. As the library doesn't (currently) have a built-in mechanism to retrieve RTT the server should also set a timer as a fallback mechanism.


In gRPC Swift this is managed by a separate channel handler with a number of different behaviours, many of which are applicable to http servers in general. These include:

As these are generally useful it may make sense to fold these behaviours (along with the graceful shutdown) either into the NIOHTTP2Handler or into a separate channel handler within swift-nio-http2.