From 04e0e019f50e3c68c834a766d38bf3d602730ddd Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Wed, 12 Feb 2020 16:13:08 -0500 Subject: [PATCH 1/2] add syncClose method to MongoClient --- Sources/MongoSwift/MongoClient.swift | 14 ++++++++++++++ Sources/MongoSwift/Operations/Operation.swift | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/Sources/MongoSwift/MongoClient.swift b/Sources/MongoSwift/MongoClient.swift index 833c6c7d1..8fd3ba40a 100644 --- a/Sources/MongoSwift/MongoClient.swift +++ b/Sources/MongoSwift/MongoClient.swift @@ -301,6 +301,20 @@ public class MongoClient { } } + /** + * Closes this `MongoClient` in a blocking fashion. + * Call this method exactly once when you are finished using the client. You must ensure that all operations + * using the client have completed before calling this. + * + * This method must complete before the `EventLoopGroup` provided to this client's constructor is shut down. + */ + public func syncClose() { + self.connectionPool.close() + self.isClosed = true + // TODO: SWIFT-349 log any errors encountered here. + try? self.operationExecutor.syncClose() + } + /// Starts a new `ClientSession` with the provided options. When you are done using this session, you must call /// `ClientSession.end()` on it. public func startSession(options: ClientSessionOptions? = nil) -> ClientSession { diff --git a/Sources/MongoSwift/Operations/Operation.swift b/Sources/MongoSwift/Operations/Operation.swift index 8775807f2..a92435286 100644 --- a/Sources/MongoSwift/Operations/Operation.swift +++ b/Sources/MongoSwift/Operations/Operation.swift @@ -37,6 +37,11 @@ internal class OperationExecutor { return promise.futureResult } + /// Closes the executor's underlying thread pool synchronously. + internal func syncClose() throws { + try self.threadPool.syncShutdownGracefully() + } + internal func execute( _ operation: T, using connection: Connection? = nil, From 28fda9e569b664075bed13e19a3128ce9eaaad90 Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Thu, 13 Feb 2020 11:31:04 -0500 Subject: [PATCH 2/2] refactor close to shutdown --- Sources/MongoSwift/ConnectionPool.swift | 2 +- Sources/MongoSwift/MongoClient.swift | 19 +++++++++++-------- Sources/MongoSwiftSync/MongoClient.swift | 2 +- Tests/MongoSwiftTests/AsyncTestUtils.swift | 2 +- Tests/MongoSwiftTests/MongoClientTests.swift | 2 +- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Sources/MongoSwift/ConnectionPool.swift b/Sources/MongoSwift/ConnectionPool.swift index b0d43d5e6..fa75b0c54 100644 --- a/Sources/MongoSwift/ConnectionPool.swift +++ b/Sources/MongoSwift/ConnectionPool.swift @@ -59,7 +59,7 @@ internal class ConnectionPool { } /// Closes the pool, cleaning up underlying resources. This method blocks as it sends `endSessions` to the server. - internal func close() { + internal func shutdown() { switch self.state { case let .open(pool): mongoc_client_pool_destroy(pool) diff --git a/Sources/MongoSwift/MongoClient.swift b/Sources/MongoSwift/MongoClient.swift index 8fd3ba40a..f957c072d 100644 --- a/Sources/MongoSwift/MongoClient.swift +++ b/Sources/MongoSwift/MongoClient.swift @@ -288,12 +288,13 @@ public class MongoClient { assert(self.isClosed, "MongoClient was not closed before deinitialization") } - /// Closes this `MongoClient`. Call this method exactly once when you are finished using the client. You must - /// ensure that all operations using the client have completed before calling this. The returned future must be - /// fulfilled before the `EventLoopGroup` provided to this client's constructor is shut down. - public func close() -> EventLoopFuture { + /// Shuts this `MongoClient` down, closing all connection to the server and cleaning up internal state. + /// Call this method exactly once when you are finished using the client. You must ensure that all operations + /// using the client have completed before calling this. The returned future must be fulfilled before the + /// `EventLoopGroup` provided to this client's constructor is shut down. + public func shutdown() -> EventLoopFuture { return self.operationExecutor.execute { - self.connectionPool.close() + self.connectionPool.shutdown() self.isClosed = true } .flatMap { @@ -302,14 +303,16 @@ public class MongoClient { } /** - * Closes this `MongoClient` in a blocking fashion. + * Shuts this `MongoClient` down in a blocking fashion, closing all connections to the server and cleaning up + * internal state. + * * Call this method exactly once when you are finished using the client. You must ensure that all operations * using the client have completed before calling this. * * This method must complete before the `EventLoopGroup` provided to this client's constructor is shut down. */ - public func syncClose() { - self.connectionPool.close() + public func syncShutdown() { + self.connectionPool.shutdown() self.isClosed = true // TODO: SWIFT-349 log any errors encountered here. try? self.operationExecutor.syncClose() diff --git a/Sources/MongoSwiftSync/MongoClient.swift b/Sources/MongoSwiftSync/MongoClient.swift index d1cc4d76c..40d2296d0 100644 --- a/Sources/MongoSwiftSync/MongoClient.swift +++ b/Sources/MongoSwiftSync/MongoClient.swift @@ -53,7 +53,7 @@ public class MongoClient { deinit { do { - try self.asyncClient.close().wait() + try self.asyncClient.shutdown().wait() } catch { assertionFailure("Error closing async client: \(error)") } diff --git a/Tests/MongoSwiftTests/AsyncTestUtils.swift b/Tests/MongoSwiftTests/AsyncTestUtils.swift index aa07ecef0..27b19900d 100644 --- a/Tests/MongoSwiftTests/AsyncTestUtils.swift +++ b/Tests/MongoSwiftTests/AsyncTestUtils.swift @@ -22,7 +22,7 @@ extension MongoClient { internal func syncCloseOrFail() { do { - try self.close().wait() + try self.shutdown().wait() } catch { XCTFail("Error closing test client: \(error)") } diff --git a/Tests/MongoSwiftTests/MongoClientTests.swift b/Tests/MongoSwiftTests/MongoClientTests.swift index 086eb40a8..3a85b1108 100644 --- a/Tests/MongoSwiftTests/MongoClientTests.swift +++ b/Tests/MongoSwiftTests/MongoClientTests.swift @@ -8,7 +8,7 @@ final class MongoClientTests: MongoSwiftTestCase { let elg = MultiThreadedEventLoopGroup(numberOfThreads: 1) defer { elg.syncShutdownOrFail() } let client = try MongoClient(using: elg) - try client.close().wait() + try client.shutdown().wait() expect(try client.listDatabases().wait()).to(throwError(MongoClient.ClosedClientError)) }