@@ -55,13 +55,17 @@ actor DatabasePool {
5555 print ( " ℹ️ availableDatabases " , availableDatabases. count)
5656 for db in availableDatabases {
5757 print ( " ℹ️ setting up db \( db. port) " )
58- // try await db.setup(for: .testing)
58+ try await db. setup ( for: . testing)
5959 print ( " ℹ️ DONE setting up db \( db. port) " )
6060 }
6161 }
6262
6363 func tearDown( ) async throws {
64- try await tearDown ( databases: runningDatabases ( ) )
64+ if isRunningInCI ( ) {
65+ // Let the CI system deal with the databases, there's nothing we can or should do here.
66+ } else {
67+ try await tearDown ( databases: runningDatabases ( ) )
68+ }
6569 }
6670
6771 func tearDown( databases: any Collection < Database > ) async throws {
@@ -182,8 +186,11 @@ extension DatabasePool.Database {
182186 }
183187
184188 func createSchema( _ environment: Environment , details: ConnectionDetails ) async throws {
189+ let start = Date ( )
190+ print ( " ℹ️ \( #function) start " )
191+ defer { print ( " ℹ️ \( #function) end " , Date ( ) . timeIntervalSince ( start) ) }
185192 do {
186- try await _withDatabase ( " postgres " , details: details) { // Connect to `postgres` db in order to reset the test db
193+ try await _withDatabase ( " postgres " , details: details, timeout : . seconds ( 1 ) ) { // Connect to `postgres` db in order to reset the test db
187194 let databaseName = Environment . get ( " DATABASE_NAME " ) !
188195 try await $0. query ( PostgresQuery ( unsafeSQL: " DROP DATABASE IF EXISTS \( databaseName) WITH (FORCE) " ) )
189196 try await $0. query ( PostgresQuery ( unsafeSQL: " CREATE DATABASE \( databaseName) " ) )
@@ -203,10 +210,13 @@ extension DatabasePool.Database {
203210 }
204211
205212 func createSnapshot( details: ConnectionDetails ) async throws {
213+ let start = Date ( )
214+ print ( " ℹ️ \( #function) start " )
215+ defer { print ( " ℹ️ \( #function) end " , Date ( ) . timeIntervalSince ( start) ) }
206216 let original = Environment . get ( " DATABASE_NAME " ) !
207217 let snapshot = original + " _snapshot "
208218 do {
209- try await _withDatabase ( " postgres " , details: details) { client in
219+ try await _withDatabase ( " postgres " , details: details, timeout : . seconds ( 1 ) ) { client in
210220 try await client. query ( PostgresQuery ( unsafeSQL: " DROP DATABASE IF EXISTS \( snapshot) WITH (FORCE) " ) )
211221 try await client. query ( PostgresQuery ( unsafeSQL: " CREATE DATABASE \( snapshot) TEMPLATE \( original) " ) )
212222 }
@@ -221,7 +231,7 @@ extension DatabasePool.Database {
221231 let snapshot = original + " _snapshot "
222232 // delete db and re-create from snapshot
223233 do {
224- try await _withDatabase ( " postgres " , details: details) { client in
234+ try await _withDatabase ( " postgres " , details: details, timeout : . seconds ( 1 ) ) { client in
225235 try await client. query ( PostgresQuery ( unsafeSQL: " DROP DATABASE IF EXISTS \( original) WITH (FORCE) " ) )
226236 try await client. query ( PostgresQuery ( unsafeSQL: " CREATE DATABASE \( original) TEMPLATE \( snapshot) " ) )
227237 }
@@ -250,14 +260,18 @@ private func connect(to databaseName: String, details: DatabasePool.Database.Con
250260
251261private func _withDatabase( _ databaseName: String ,
252262 details: DatabasePool . Database . ConnectionDetails ,
253- _ query: @escaping ( PostgresClient ) async throws -> Void ) async throws {
263+ timeout: Duration ,
264+ _ query: @Sendable @escaping ( PostgresClient) async throws -> Void ) async throws {
254265 let client = connect ( to: databaseName, details: details)
255- try await withThrowingTaskGroup { taskGroup in
256- taskGroup. addTask { await client. run ( ) }
257-
258- try await query ( client)
259-
260- taskGroup. cancelAll ( )
266+ try await run ( timeout: timeout) {
267+ try await withThrowingTaskGroup { taskGroup in
268+ taskGroup. addTask { await client. run ( ) }
269+ taskGroup. addTask {
270+ try await query ( client)
271+ }
272+ try await taskGroup. next ( )
273+ taskGroup. cancelAll ( )
274+ }
261275 }
262276}
263277
@@ -275,3 +289,35 @@ extension Environment {
275289
276290#warning("remove later")
277291extension String : Swift . Error { }
292+
293+
294+ private enum TimeoutError : Error {
295+ case timeout
296+ case noResult
297+ }
298+
299+
300+ private func run( timeout: Duration , operation: @escaping @Sendable ( ) async throws -> Void ) async throws {
301+ try await withThrowingTaskGroup ( of: Bool . self) { group in
302+ group. addTask {
303+ try ? await Task . sleep ( for: timeout)
304+ return false
305+ }
306+ group. addTask {
307+ try await operation ( )
308+ return true
309+ }
310+ let res = await group. nextResult ( )
311+ group. cancelAll ( )
312+ switch res {
313+ case . success( false ) :
314+ throw TimeoutError . timeout
315+ case . success( true ) :
316+ break
317+ case . failure( let error) :
318+ throw error
319+ case . none:
320+ throw TimeoutError . noResult
321+ }
322+ }
323+ }
0 commit comments