From dc40e0bc4bd611fd38ae17411b6d1036d769b15b Mon Sep 17 00:00:00 2001 From: gcjenkinson Date: Wed, 8 Sep 2021 09:46:53 +0100 Subject: [PATCH] New configuration parameter for HTTP2 maxFrameSize. Motivation: In gRPC calls that process large payloads, the default settings of the HTTP2 maxFrameSize (16384) within swift-nio-http2 results in significant performance impact (for large payloads this performance impact has been demonstrated to result in timeouts where RPCs fail to complete within their assigned deadline). Allowing programmatic configuration of the HTTP2 maxFrameSize when the server is built allows the parameter to be optimised for the expected payload sizes. Modifications: Added new gRPC configuration parameter for the HTTP2 parameter maxFrameSize (which can be configured in the Server.Builder using the new method `withHTTPMaxFrameSize()`). Result: The Server.Builder can be used to configure the HTTP2 maxFrameSize parameter as: Server.insecure(group: serverGroup).withHTTPMaxFrameSize(1024 * 1024)... --- Sources/GRPC/GRPCServerPipelineConfigurator.swift | 4 ++++ Sources/GRPC/Server.swift | 14 ++++++++++++++ Sources/GRPC/ServerBuilder.swift | 8 ++++++++ 3 files changed, 26 insertions(+) diff --git a/Sources/GRPC/GRPCServerPipelineConfigurator.swift b/Sources/GRPC/GRPCServerPipelineConfigurator.swift index 39aee8267..218eea213 100644 --- a/Sources/GRPC/GRPCServerPipelineConfigurator.swift +++ b/Sources/GRPC/GRPCServerPipelineConfigurator.swift @@ -90,6 +90,10 @@ final class GRPCServerPipelineConfigurator: ChannelInboundHandler, RemovableChan parameter: .maxHeaderListSize, value: HPACKDecoder.defaultMaxHeaderListSize ), + HTTP2Setting( + parameter: .maxFrameSize, + value: self.configuration.httpMaxFrameSize + ), ] ) } diff --git a/Sources/GRPC/Server.swift b/Sources/GRPC/Server.swift index 7031fab2d..0d5269f5f 100644 --- a/Sources/GRPC/Server.swift +++ b/Sources/GRPC/Server.swift @@ -332,6 +332,14 @@ extension Server { } } + /// The HTTP/2 max frame size. Defaults to 16384. Value is clamped between 2^14 and 2^24-1 + /// octets inclusive (the minimum and maximum allowable values - HTTP/2 RFC 7540 4.2). + public var httpMaxFrameSize: Int = 16384 { + didSet(httpMaxFrameSize) { + self.httpMaxFrameSize = httpMaxFrameSize.clamped(to: 16384 ... 16_777_215) + } + } + /// The root server logger. Accepted connections will branch from this logger and RPCs on /// each connection will use a logger branched from the connections logger. This logger is made /// available to service providers via `context`. Defaults to a no-op logger. @@ -447,3 +455,9 @@ private extension ServerBootstrapProtocol { } } } + +extension Comparable { + fileprivate func clamped(to range: ClosedRange) -> Self { + return min(max(self, range.lowerBound), range.upperBound) + } +} diff --git a/Sources/GRPC/ServerBuilder.swift b/Sources/GRPC/ServerBuilder.swift index 03219918c..bdbdbde9a 100644 --- a/Sources/GRPC/ServerBuilder.swift +++ b/Sources/GRPC/ServerBuilder.swift @@ -168,6 +168,14 @@ extension Server.Builder { } } +extension Server.Builder { + @discardableResult + public func withHTTPMaxFrameSize(_ httpMaxFrameSize: Int) -> Self { + self.configuration.httpMaxFrameSize = httpMaxFrameSize + return self + } +} + extension Server.Builder { /// Sets the root server logger. Accepted connections will branch from this logger and RPCs on /// each connection will use a logger branched from the connections logger. This logger is made