@@ -228,11 +228,22 @@ extension HTTPConnectionPool {
228
228
private mutating func _newHTTP2ConnectionEstablished( _ connection: Connection , maxConcurrentStreams: Int ) -> EstablishedAction {
229
229
self . failedConsecutiveConnectionAttempts = 0
230
230
self . lastConnectFailure = nil
231
- let ( index, context) = self . connections. newHTTP2ConnectionEstablished (
232
- connection,
233
- maxConcurrentStreams: maxConcurrentStreams
234
- )
235
- return self . nextActionForAvailableConnection ( at: index, context: context)
231
+ if self . connections. hasActiveConnection ( for: connection. eventLoop) {
232
+ guard let ( index, _) = self . connections. failConnection ( connection. id) else {
233
+ preconditionFailure ( " we connection to a connection which we no nothing about " )
234
+ }
235
+ self . connections. removeConnection ( at: index)
236
+ return . init(
237
+ request: . none,
238
+ connection: . closeConnection( connection, isShutdown: . no)
239
+ )
240
+ } else {
241
+ let ( index, context) = self . connections. newHTTP2ConnectionEstablished (
242
+ connection,
243
+ maxConcurrentStreams: maxConcurrentStreams
244
+ )
245
+ return self . nextActionForAvailableConnection ( at: index, context: context)
246
+ }
236
247
}
237
248
238
249
private mutating func nextActionForAvailableConnection(
@@ -318,18 +329,35 @@ extension HTTPConnectionPool {
318
329
private mutating func nextActionForFailedConnection( at index: Int , on eventLoop: EventLoop ) -> Action {
319
330
switch self . state {
320
331
case . running:
321
- let hasPendingRequest = !self . requests. isEmpty ( for: eventLoop) || !self . requests. isEmpty ( for: nil )
322
- guard hasPendingRequest else {
332
+ // we do not know if we have created this connection for a request with a required
333
+ // event loop or not. However, we do not need this information and can infer
334
+ // if we need to create a new connection because we will only ever create one connection
335
+ // per event loop for required event loop requests and only need one connection for
336
+ // general purpose requests.
337
+
338
+ // we need to start a new on connection in two cases:
339
+ if
340
+ // 1. if we have general purpose requests
341
+ self . requests. isEmpty ( for: nil ) &&
342
+ // and no connection starting or active
343
+ self . connections. hasStartingOrActiveConnection ( ) ||
344
+ // 2. or if we have requests for a required event loop
345
+ self . requests. isEmpty ( for: eventLoop) &&
346
+ // and no connection starting or active for the given event loop
347
+ self . connections. hasStartingOrActiveConnection ( for: eventLoop) {
348
+ let ( newConnectionID, previousEventLoop) = self . connections. createNewConnectionByReplacingClosedConnection ( at: index)
349
+ precondition ( previousEventLoop === eventLoop)
350
+
351
+ return . init(
352
+ request: . none,
353
+ connection: . createConnection( newConnectionID, on: eventLoop)
354
+ )
355
+ } else {
356
+ // otherwise we can remove the connection
357
+ self . connections. removeConnection ( at: index)
323
358
return . none
324
359
}
325
360
326
- let ( newConnectionID, previousEventLoop) = self . connections. createNewConnectionByReplacingClosedConnection ( at: index)
327
- precondition ( previousEventLoop === eventLoop)
328
-
329
- return . init(
330
- request: . none,
331
- connection: . createConnection( newConnectionID, on: eventLoop)
332
- )
333
361
case . shuttingDown( let unclean) :
334
362
assert ( self . requests. isEmpty)
335
363
self . connections. removeConnection ( at: index)
0 commit comments