Skip to content

Commit 3370a94

Browse files
authored
Add support for configuring backpressure (#14)
1 parent 2b0eec8 commit 3370a94

File tree

2 files changed

+52
-7
lines changed

2 files changed

+52
-7
lines changed

Sources/HTTPServer/HTTPServer.swift

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,21 @@ public final class Server<RequestHandler: HTTPServerRequestHandler> {
155155
configuration: HTTPServerConfiguration,
156156
handler: RequestHandler
157157
) async throws {
158+
let asyncChannelConfiguration: NIOAsyncChannel<HTTPRequestPart, HTTPResponsePart>.Configuration
159+
switch configuration.backpressureStrategy.backing {
160+
case .watermark(let low, let high):
161+
asyncChannelConfiguration = .init(
162+
backPressureStrategy: .init(lowWatermark: low, highWatermark: high),
163+
isOutboundHalfClosureEnabled: true
164+
)
165+
}
166+
158167
switch configuration.tlSConfiguration.backing {
159168
case .insecure:
160169
try await Self.serveInsecureHTTP1_1(
161170
bindTarget: configuration.bindTarget,
162171
handler: handler,
172+
asyncChannelConfiguration: asyncChannelConfiguration,
163173
logger: logger
164174
)
165175

@@ -169,6 +179,7 @@ public final class Server<RequestHandler: HTTPServerRequestHandler> {
169179
certificateChain: certificateChain,
170180
privateKey: privateKey,
171181
handler: handler,
182+
asyncChannelConfiguration: asyncChannelConfiguration,
172183
logger: logger
173184
)
174185
}
@@ -177,6 +188,7 @@ public final class Server<RequestHandler: HTTPServerRequestHandler> {
177188
private static func serveInsecureHTTP1_1(
178189
bindTarget: HTTPServerConfiguration.BindTarget,
179190
handler: RequestHandler,
191+
asyncChannelConfiguration: NIOAsyncChannel<HTTPRequestPart, HTTPResponsePart>.Configuration,
180192
logger: Logger
181193
) async throws {
182194
switch bindTarget.backing {
@@ -188,7 +200,7 @@ public final class Server<RequestHandler: HTTPServerRequestHandler> {
188200
try channel.pipeline.syncOperations.addHandler(HTTP1ToHTTPServerCodec(secure: false))
189201
return try NIOAsyncChannel<HTTPRequestPart, HTTPResponsePart>(
190202
wrappingChannelSynchronously: channel,
191-
configuration: .init(isOutboundHalfClosureEnabled: true)
203+
configuration: asyncChannelConfiguration
192204
)
193205
}
194206
}
@@ -214,6 +226,7 @@ public final class Server<RequestHandler: HTTPServerRequestHandler> {
214226
certificateChain: [Certificate],
215227
privateKey: Certificate.PrivateKey,
216228
handler: RequestHandler,
229+
asyncChannelConfiguration: NIOAsyncChannel<HTTPRequestPart, HTTPResponsePart>.Configuration,
217230
logger: Logger
218231
) async throws {
219232
switch bindTarget.backing {
@@ -256,7 +269,7 @@ public final class Server<RequestHandler: HTTPServerRequestHandler> {
256269

257270
return try NIOAsyncChannel<HTTPRequestPart, HTTPResponsePart>(
258271
wrappingChannelSynchronously: channel,
259-
configuration: .init(isOutboundHalfClosureEnabled: true)
272+
configuration: asyncChannelConfiguration
260273
)
261274
}
262275
} http2ConnectionInitializer: { channel in
@@ -270,7 +283,7 @@ public final class Server<RequestHandler: HTTPServerRequestHandler> {
270283

271284
return try NIOAsyncChannel<HTTPRequestPart, HTTPResponsePart>(
272285
wrappingChannelSynchronously: channel,
273-
configuration: .init(isOutboundHalfClosureEnabled: true)
286+
configuration: asyncChannelConfiguration
274287
)
275288
}
276289
}

Sources/HTTPServer/HTTPServerConfiguration.swift

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,7 @@ public struct HTTPServerConfiguration: Sendable {
4848

4949
let backing: Backing
5050

51-
public static func insecure() -> Self {
52-
Self(backing: .insecure)
53-
}
51+
public static let insecure: Self = Self(backing: .insecure)
5452

5553
public static func certificateChainAndPrivateKey(
5654
certificateChain: [Certificate],
@@ -65,16 +63,50 @@ public struct HTTPServerConfiguration: Sendable {
6563
}
6664
}
6765

66+
/// Configuration for the backpressure strategy to use when reading requests and writing back responses.
67+
public struct BackPressureStrategy: Sendable {
68+
enum Backing {
69+
case watermark(low: Int, high: Int)
70+
}
71+
72+
internal let backing: Backing
73+
74+
private init(backing: Backing) {
75+
self.backing = backing
76+
}
77+
78+
/// A low/high watermark will be applied when reading requests and writing responses.
79+
/// - Parameters:
80+
/// - low: The threshold below which the consumer will ask the producer to produce more elements.
81+
/// - high: The threshold above which the producer will stop producing elements.
82+
/// - Returns: A low/high watermark strategy with the configured thresholds.
83+
public static func watermark(low: Int, high: Int) -> Self {
84+
.init(backing: .watermark(low: low, high: high))
85+
}
86+
}
87+
6888
/// Network binding configuration
6989
public var bindTarget: BindTarget
7090

91+
/// TLS configuration for the server.
7192
public var tlSConfiguration: TLSConfiguration
7293

94+
/// Backpressure strategy to use in the server.
95+
public var backpressureStrategy: BackPressureStrategy
96+
97+
/// Create a new configuration.
98+
/// - Parameters:
99+
/// - bindTarget: A ``BindTarget``.
100+
/// - tlsConfiguration: A ``TLSConfiguration``. Defaults to ``TLSConfiguration/insecure``.
101+
/// - backpressureStrategy: A ``BackPressureStrategy``.
102+
/// Defaults to ``BackPressureStrategy/watermark(low:high:)`` with a low watermark of 2 and a high of 10.
73103
public init(
74104
bindTarget: BindTarget,
75-
tlsConfiguration: TLSConfiguration = .insecure()
105+
tlsConfiguration: TLSConfiguration = .insecure,
106+
backpressureStrategy: BackPressureStrategy = .watermark(low: 2, high: 10)
76107
) {
77108
self.bindTarget = bindTarget
78109
self.tlSConfiguration = tlsConfiguration
110+
self.backpressureStrategy = backpressureStrategy
79111
}
80112
}

0 commit comments

Comments
 (0)