@@ -21,7 +21,7 @@ protocol HTTPConnectionPoolDelegate {
2121 func connectionPoolDidShutdown( _ pool: HTTPConnectionPool , unclean: Bool )
2222}
2323
24- class HTTPConnectionPool {
24+ final class HTTPConnectionPool {
2525 struct Connection : Hashable {
2626 typealias ID = Int
2727
@@ -92,14 +92,14 @@ class HTTPConnectionPool {
9292
9393 /// Closes the connection without cancelling running requests. Use this when you are sure, that the
9494 /// connection is currently idle.
95- fileprivate func close( ) -> EventLoopFuture < Void > {
95+ fileprivate func close( promise : EventLoopPromise < Void > ? ) {
9696 switch self . _ref {
9797 case . http1_1( let connection) :
98- return connection. close ( )
98+ return connection. close ( promise : promise )
9999 case . http2( let connection) :
100- return connection. close ( )
101- case . __testOnly_connection( _ , let eventLoop ) :
102- return eventLoop . makeSucceededFuture ( ( ) )
100+ return connection. close ( promise : promise )
101+ case . __testOnly_connection:
102+ promise ? . succeed ( ( ) )
103103 }
104104 }
105105
@@ -139,18 +139,20 @@ class HTTPConnectionPool {
139139 }
140140 }
141141
142- let timerLock = Lock ( )
142+ static let fallbackConnectTimeout : TimeAmount = . seconds( 30 )
143+
144+ private let timerLock = Lock ( )
143145 private var _requestTimer = [ Request . ID : Scheduled < Void > ] ( )
144146 private var _idleTimer = [ Connection . ID : Scheduled < Void > ] ( )
145147 private var _backoffTimer = [ Connection . ID : Scheduled < Void > ] ( )
146148
147- let key : ConnectionPool . Key
148- var logger : Logger
149+ private let key : ConnectionPool . Key
150+ private var logger : Logger
149151
150- let eventLoopGroup : EventLoopGroup
151- let connectionFactory : ConnectionFactory
152- let clientConfiguration : HTTPClient . Configuration
153- let idleConnectionTimeout : TimeAmount
152+ private let eventLoopGroup : EventLoopGroup
153+ private let connectionFactory : ConnectionFactory
154+ private let clientConfiguration : HTTPClient . Configuration
155+ private let idleConnectionTimeout : TimeAmount
154156
155157 let delegate : HTTPConnectionPoolDelegate
156158
@@ -197,12 +199,14 @@ class HTTPConnectionPool {
197199 self . run ( action: action)
198200 }
199201
200- func run( action: StateMachine . Action ) {
202+ // MARK: Run actions
203+
204+ private func run( action: StateMachine . Action ) {
201205 self . runConnectionAction ( action. connection)
202206 self . runRequestAction ( action. request)
203207 }
204208
205- func runConnectionAction( _ action: StateMachine . ConnectionAction ) {
209+ private func runConnectionAction( _ action: StateMachine . ConnectionAction ) {
206210 switch action {
207211 case . createConnection( let connectionID, let eventLoop) :
208212 self . createConnection ( connectionID, on: eventLoop)
@@ -218,19 +222,19 @@ class HTTPConnectionPool {
218222
219223 case . closeConnection( let connection, isShutdown: let isShutdown) :
220224 // we are not interested in the close future...
221- _ = connection. close ( )
225+ connection. close ( promise : nil )
222226
223227 if case . yes( let unclean) = isShutdown {
224228 self . delegate. connectionPoolDidShutdown ( self , unclean: unclean)
225229 }
226230
227231 case . cleanupConnections( let cleanupContext, isShutdown: let isShutdown) :
228232 for connection in cleanupContext. close {
229- _ = connection. close ( )
233+ connection. close ( promise : nil )
230234 }
231235
232236 for connection in cleanupContext. cancel {
233- _ = connection. close ( )
237+ connection. close ( promise : nil )
234238 }
235239
236240 for connectionID in cleanupContext. connectBackoff {
@@ -246,7 +250,11 @@ class HTTPConnectionPool {
246250 }
247251 }
248252
249- func runRequestAction( _ action: StateMachine . RequestAction ) {
253+ private func runRequestAction( _ action: StateMachine . RequestAction ) {
254+ // The order of execution fail/execute request vs cancelling the request timeout timer does
255+ // not matter in the actions here. The actions don't cause any side effects that will be
256+ // reported back to the state machine and are not dependent on each other.
257+
250258 switch action {
251259 case . executeRequest( let request, let connection, cancelTimeout: let cancelTimeout) :
252260 connection. executeRequest ( request. req)
@@ -255,10 +263,8 @@ class HTTPConnectionPool {
255263 }
256264
257265 case . executeRequestsAndCancelTimeouts( let requests, let connection) :
258- for request in requests {
259- connection. executeRequest ( request. req)
260- self . cancelRequestTimeout ( request. id)
261- }
266+ requests. forEach { connection. executeRequest ( $0. req) }
267+ self . cancelRequestTimeouts ( requests)
262268
263269 case . failRequest( let request, let error, cancelTimeout: let cancelTimeout) :
264270 if cancelTimeout {
@@ -267,10 +273,8 @@ class HTTPConnectionPool {
267273 request. req. fail ( error)
268274
269275 case . failRequestsAndCancelTimeouts( let requests, let error) :
270- for request in requests {
271- self . cancelRequestTimeout ( request. id)
272- request. req. fail ( error)
273- }
276+ requests. forEach { $0. req. fail ( error) }
277+ self . cancelRequestTimeouts ( requests)
274278
275279 case . scheduleRequestTimeout( let request, on: let eventLoop) :
276280 self . scheduleRequestTimeout ( request, on: eventLoop)
@@ -283,15 +287,15 @@ class HTTPConnectionPool {
283287 }
284288 }
285289
286- // MARK: Run actions
287-
288290 private func createConnection( _ connectionID: Connection . ID , on eventLoop: EventLoop ) {
291+ // Even though this function is called make it actually creates/establishes a connection.
292+ // TBD: Should we rename it? To what?
289293 self . connectionFactory. makeConnection (
290294 for: self ,
291295 connectionID: connectionID,
292296 http1ConnectionDelegate: self ,
293297 http2ConnectionDelegate: self ,
294- deadline: . now( ) + ( self . clientConfiguration. timeout. connect ?? . seconds ( 30 ) ) ,
298+ deadline: . now( ) + ( self . clientConfiguration. timeout. connect ?? Self . fallbackConnectTimeout ) ,
295299 eventLoop: eventLoop,
296300 logger: self . logger
297301 )
@@ -303,17 +307,16 @@ class HTTPConnectionPool {
303307 // The timer has fired. Now we need to do a couple of things:
304308 //
305309 // 1. Remove ourselves from the timer dictionary to not leak any data. If our
306- // waiter entry still exist , we need to tell the state machine, that we want
310+ // waiter entry still exists , we need to tell the state machine, that we want
307311 // to fail the request.
308-
309- let timeout = self . timerLock. withLock {
312+ let timeoutFired = self . timerLock. withLock {
310313 self . _requestTimer. removeValue ( forKey: requestID) != nil
311314 }
312315
313316 // 2. If the entry did not exists anymore, we can assume that the request was
314317 // scheduled on another connection. The timer still fired anyhow because of a
315318 // race. In such a situation we don't need to do anything.
316- guard timeout else { return }
319+ guard timeoutFired else { return }
317320
318321 // 3. Tell the state machine about the timeout
319322 let action = self . stateLock. withLock {
@@ -339,6 +342,15 @@ class HTTPConnectionPool {
339342 scheduled? . cancel ( )
340343 }
341344
345+ private func cancelRequestTimeouts( _ requests: [ Request ] ) {
346+ let scheduled = self . timerLock. withLock {
347+ requests. compactMap {
348+ self . _requestTimer. removeValue ( forKey: $0. id)
349+ }
350+ }
351+ scheduled. forEach { $0. cancel ( ) }
352+ }
353+
342354 private func scheduleIdleTimerForConnection( _ connectionID: Connection . ID , on eventLoop: EventLoop ) {
343355 let scheduled = eventLoop. scheduleTask ( in: self . idleConnectionTimeout) {
344356 // there might be a race between a cancelTimer call and the triggering
0 commit comments