Skip to content

Commit 5d2bf92

Browse files
authored
Ensure HTTPConnectionPool calls shutdown on active connections. (#422)
Trigger the correct method on HTTPConnectionPool.Connection to cancel the request and close the connection.
1 parent fb49c1b commit 5d2bf92

File tree

3 files changed

+55
-4
lines changed

3 files changed

+55
-4
lines changed

Diff for: Sources/AsyncHTTPClient/ConnectionPool/HTTPConnectionPool.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ final class HTTPConnectionPool {
235235
}
236236

237237
for connection in cleanupContext.cancel {
238-
connection.close(promise: nil)
238+
connection.shutdown()
239239
}
240240

241241
for connectionID in cleanupContext.connectBackoff {

Diff for: Tests/AsyncHTTPClientTests/HTTPConnectionPoolTests+XCTest.swift

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ extension HTTPConnectionPoolTests {
3131
("testConnectionCreationIsRetriedUntilRequestIsFailed", testConnectionCreationIsRetriedUntilRequestIsFailed),
3232
("testConnectionCreationIsRetriedUntilPoolIsShutdown", testConnectionCreationIsRetriedUntilPoolIsShutdown),
3333
("testConnectionCreationIsRetriedUntilRequestIsCancelled", testConnectionCreationIsRetriedUntilRequestIsCancelled),
34+
("testConnectionShutdownIsCalledOnActiveConnections", testConnectionShutdownIsCalledOnActiveConnections),
3435
]
3536
}
3637
}

Diff for: Tests/AsyncHTTPClientTests/HTTPConnectionPoolTests.swift

+53-3
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ class HTTPConnectionPoolTests: XCTestCase {
294294
let eventLoop = eventLoopGroup.next()
295295
defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) }
296296

297-
let request = try! HTTPClient.Request(url: "http://localhost:9000")
297+
let request = try! HTTPClient.Request(url: "http://localhost:\(httpBin.port)")
298298
let poolDelegate = TestDelegate(eventLoop: eventLoop)
299299

300300
let pool = HTTPConnectionPool(
@@ -318,7 +318,7 @@ class HTTPConnectionPoolTests: XCTestCase {
318318

319319
var maybeRequest: HTTPClient.Request?
320320
var maybeRequestBag: RequestBag<ResponseAccumulator>?
321-
XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "https://localhost:\(httpBin.port)"))
321+
XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost:\(httpBin.port)"))
322322
XCTAssertNoThrow(maybeRequestBag = try RequestBag(
323323
request: XCTUnwrap(maybeRequest),
324324
eventLoopPreference: .indifferent,
@@ -332,13 +332,63 @@ class HTTPConnectionPoolTests: XCTestCase {
332332
guard let requestBag = maybeRequestBag else { return XCTFail("Expected to get a request") }
333333

334334
pool.executeRequest(requestBag)
335-
XCTAssertNoThrow(try eventLoop.scheduleTask(in: .milliseconds(100)) {}.futureResult.wait())
335+
XCTAssertNoThrow(try eventLoop.scheduleTask(in: .seconds(1)) {}.futureResult.wait())
336336
requestBag.cancel()
337337

338338
XCTAssertThrowsError(try requestBag.task.futureResult.wait()) {
339339
XCTAssertEqual($0 as? HTTPClientError, .cancelled)
340340
}
341+
XCTAssertGreaterThanOrEqual(httpBin.createdConnections, 3)
342+
}
343+
344+
func testConnectionShutdownIsCalledOnActiveConnections() {
345+
let httpBin = HTTPBin()
346+
defer { XCTAssertNoThrow(try httpBin.shutdown()) }
347+
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
348+
let eventLoop = eventLoopGroup.next()
349+
defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) }
350+
351+
let request = try! HTTPClient.Request(url: "http://localhost:\(httpBin.port)")
352+
let poolDelegate = TestDelegate(eventLoop: eventLoop)
353+
354+
let pool = HTTPConnectionPool(
355+
eventLoopGroup: eventLoopGroup,
356+
sslContextCache: .init(),
357+
tlsConfiguration: .none,
358+
clientConfiguration: .init(),
359+
key: .init(request),
360+
delegate: poolDelegate,
361+
idGenerator: .init(),
362+
backgroundActivityLogger: .init(label: "test")
363+
)
364+
365+
var maybeRequest: HTTPClient.Request?
366+
var maybeRequestBag: RequestBag<ResponseAccumulator>?
367+
XCTAssertNoThrow(maybeRequest = try HTTPClient.Request(url: "http://localhost:\(httpBin.port)/wait"))
368+
XCTAssertNoThrow(maybeRequestBag = try RequestBag(
369+
request: XCTUnwrap(maybeRequest),
370+
eventLoopPreference: .indifferent,
371+
task: .init(eventLoop: eventLoopGroup.next(), logger: .init(label: "test")),
372+
redirectHandler: nil,
373+
connectionDeadline: .now() + .seconds(5),
374+
idleReadTimeout: nil,
375+
delegate: ResponseAccumulator(request: XCTUnwrap(maybeRequest))
376+
))
377+
378+
guard let requestBag = maybeRequestBag else { return XCTFail("Expected to get a request") }
379+
380+
pool.executeRequest(requestBag)
381+
XCTAssertNoThrow(try eventLoop.scheduleTask(in: .milliseconds(500)) {}.futureResult.wait())
382+
pool.shutdown()
383+
384+
XCTAssertNoThrow(try poolDelegate.future.wait())
385+
386+
XCTAssertThrowsError(try requestBag.task.futureResult.wait()) {
387+
XCTAssertEqual($0 as? HTTPClientError, .cancelled)
388+
}
389+
341390
XCTAssertGreaterThanOrEqual(httpBin.createdConnections, 1)
391+
XCTAssertGreaterThanOrEqual(httpBin.activeConnections, 0)
342392
}
343393
}
344394

0 commit comments

Comments
 (0)