From c7600c3292722c89d9de568afeec4a7859b70ac4 Mon Sep 17 00:00:00 2001 From: Dimitri Bouniol Date: Fri, 11 Sep 2026 03:44:37 -0700 Subject: [PATCH] Added task names to every task for an improved debugging experience --- .../CodableDatastore/Datastore/Datastore.swift | 2 +- .../Helpers/AsyncFileReader.swift | 2 +- .../Helpers/Swift6.1+Compatibility.swift | 17 +++++++++++++++-- .../AsyncThrowingBackpressureStream.swift | 8 ++++---- .../Datastore/DatastoreIndex.swift | 4 ++-- .../Datastore/DatastorePage.swift | 8 ++++---- .../Datastore/DatastoreRoot.swift | 2 +- .../Datastore/PersistenceDatastore.swift | 14 +++++++------- .../Transaction/Transaction.swift | 6 +++--- 9 files changed, 38 insertions(+), 25 deletions(-) diff --git a/Sources/CodableDatastore/Datastore/Datastore.swift b/Sources/CodableDatastore/Datastore/Datastore.swift index c5a7ac1..c73ad0e 100644 --- a/Sources/CodableDatastore/Datastore/Datastore.swift +++ b/Sources/CodableDatastore/Datastore/Datastore.swift @@ -160,7 +160,7 @@ extension Datastore { if let progressHandler { warmupProgressHandlers.append(progressHandler) } - let warmupTask = Task { + let warmupTask = Task(name: "CodableDatastore.Datastore.warmupIfNeeded(progressHandler:) - Datastore: \(key)") { try await persistence._withTransaction( actionName: "Migrate \(key) Instances", options: [] diff --git a/Sources/CodableDatastore/Helpers/AsyncFileReader.swift b/Sources/CodableDatastore/Helpers/AsyncFileReader.swift index 16d8bd1..8f7b0a8 100644 --- a/Sources/CodableDatastore/Helpers/AsyncFileReader.swift +++ b/Sources/CodableDatastore/Helpers/AsyncFileReader.swift @@ -27,7 +27,7 @@ class AsyncFileReader: @unchecked Sendable { init(contentsOf url: URL) { self.url = url - self.readerTask = Task(name: "AsyncFileReader") { await self.startReading() } + self.readerTask = Task(name: "CodableDatastore.AsyncFileReader.init(contentsOf:) - File: \(url.lastPathComponent)") { await self.startReading() } } func startReading() async { diff --git a/Sources/CodableDatastore/Helpers/Swift6.1+Compatibility.swift b/Sources/CodableDatastore/Helpers/Swift6.1+Compatibility.swift index 0d62306..2e5f647 100644 --- a/Sources/CodableDatastore/Helpers/Swift6.1+Compatibility.swift +++ b/Sources/CodableDatastore/Helpers/Swift6.1+Compatibility.swift @@ -8,9 +8,22 @@ // #if compiler(<6.2) -extension Task where Failure == Never { +extension Task { @discardableResult - init(name: String?, priority: TaskPriority? = nil, operation: sending @escaping @isolated(any) () async -> Success) { + init( + name: String?, + priority: TaskPriority? = nil, + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async -> Success + ) where Failure == Never { + self.init(priority: priority, operation: operation) + } + + @discardableResult + init( + name: String?, + priority: TaskPriority? = nil, + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success + ) where Failure == any Error { self.init(priority: priority, operation: operation) } } diff --git a/Sources/CodableDatastore/Persistence/Disk Persistence/AsyncThrowingBackpressureStream.swift b/Sources/CodableDatastore/Persistence/Disk Persistence/AsyncThrowingBackpressureStream.swift index e584b53..3b092c8 100644 --- a/Sources/CodableDatastore/Persistence/Disk Persistence/AsyncThrowingBackpressureStream.swift +++ b/Sources/CodableDatastore/Persistence/Disk Persistence/AsyncThrowingBackpressureStream.swift @@ -91,7 +91,7 @@ struct AsyncThrowingBackpressureStream: Sendable { } } } onCancel: { - Task { await cancelPendingRead() } + Task(name: "CodableDatastore.AsyncThrowingBackpressureStream.consumeNext()") { await cancelPendingRead() } } } @@ -119,7 +119,7 @@ struct AsyncThrowingBackpressureStream: Sendable { continuation.resume(throwing: CancellationError()) return } - Task { + Task(name: "CodableDatastore.AsyncThrowingBackpressureStream.Continuation.yield()") { await stateMachine.provide(.success(value), in: continuation) } } as Void @@ -133,7 +133,7 @@ struct AsyncThrowingBackpressureStream: Sendable { guard let stateMachine else { continuation.resume(throwing: CancellationError()) return } - Task { + Task(name: "CodableDatastore.AsyncThrowingBackpressureStream.Continuation.finish(throwing:)") { if let error { await stateMachine.provide(.failure(error), in: continuation) } else { @@ -150,7 +150,7 @@ struct AsyncThrowingBackpressureStream: Sendable { stateMachine = StateMachine() let continuation = Continuation(stateMachine: stateMachine) - Task { + Task(name: "CodableDatastore.AsyncThrowingBackpressureStream.init(provider:)") { do { try await provider(continuation) try await continuation.finish() diff --git a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreIndex.swift b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreIndex.swift index 127622d..7ad59eb 100644 --- a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreIndex.swift +++ b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreIndex.swift @@ -45,7 +45,7 @@ extension DiskPersistence.Datastore { } deinit { - Task { [id, datastore] in + Task(name: "CodableDatastore.DiskPersistence.Datastore.Index.deinit - Index: \(id)") { [id, datastore] in await datastore.invalidate(id) } } @@ -124,7 +124,7 @@ extension DiskPersistence.Datastore.Index { get async throws { if let manifestTask { return try await manifestTask.value } - let loader = Task { + let loader = Task(name: "CodableDatastore.DiskPersistence.Datastore.Index.manifest - Index: \(id)") { if let _manifest { return _manifest } let manifest = try await DatastoreIndexManifest(contentsOf: manifestURL, id: id.manifestID) diff --git a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastorePage.swift b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastorePage.swift index 8fcc0a7..b08b509 100644 --- a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastorePage.swift +++ b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastorePage.swift @@ -35,7 +35,7 @@ extension DiskPersistence.Datastore { self.datastore = datastore self.id = id self.blocksReaderTask = blocks.map { blocks in - Task { + Task(name: "CodableDatastore.DiskPersistence.Datastore.Page.init(...) - Page: \(id)") { MultiplexedAsyncSequence(base: AnyReadableSequence(blocks)) } } @@ -43,7 +43,7 @@ extension DiskPersistence.Datastore { } deinit { - Task { [id, datastore] in + Task(name: "CodableDatastore.DiskPersistence.Datastore.Page.deinit - Page: \(id)") { [id, datastore] in await datastore.invalidate(id) } } @@ -135,7 +135,7 @@ extension DiskPersistence.Datastore.Page { return try await blocksReaderTask.value } - let readerTask = Task { + let readerTask = Task(name: "CodableDatastore.DiskPersistence.Datastore.Page.blocks - Page: \(id)") { try await performRead(sequence: readableSequence) } isPersisted = true @@ -192,7 +192,7 @@ actor MultiplexedAsyncSequence: AsyncSequence wh let lastTask: Task? = cachedEntries.last - let newTask = Task { + let newTask = Task(name: "CodableDatastore.MultiplexedAsyncSequence.subscript(_:)") { /// Make sure previous iteration finished before sourcing the next one. _ = try? await lastTask?.value diff --git a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreRoot.swift b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreRoot.swift index f5d3b19..1e04707 100644 --- a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreRoot.swift +++ b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/DatastoreRoot.swift @@ -71,7 +71,7 @@ extension DiskPersistence.Datastore { } deinit { - Task { [id, datastore] in + Task(name: "CodableDatastore.DiskPersistence.Datastore.RootObject.deinit - RootObject: \(id)") { [id, datastore] in await datastore.invalidate(id) } } diff --git a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/PersistenceDatastore.swift b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/PersistenceDatastore.swift index a7c9c0d..cc389ba 100644 --- a/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/PersistenceDatastore.swift +++ b/Sources/CodableDatastore/Persistence/Disk Persistence/Datastore/PersistenceDatastore.swift @@ -138,13 +138,13 @@ extension DiskPersistence.Datastore { // print("🤷 Cache Miss: Root \(identifier)") let rootObject = RootObject(datastore: self, id: identifier) trackedRootObjects[identifier] = WeakValue(rootObject) - Task { await snapshot.persistence.cache(rootObject) } + Task(name: "CodableDatastore.DiskPersistence.Datastore.rootObject(for:).cache - Datastore: \(id)") { await snapshot.persistence.cache(rootObject) } return rootObject } func adopt(rootObject: RootObject) { trackedRootObjects[rootObject.id] = WeakValue(rootObject) - Task { await snapshot.persistence.cache(rootObject) } + Task(name: "CodableDatastore.DiskPersistence.Datastore.adopt(rootObject:).cache - Datastore: \(id)") { await snapshot.persistence.cache(rootObject) } } func invalidate(_ identifier: RootObject.ID) { @@ -166,13 +166,13 @@ extension DiskPersistence.Datastore { // print("🤷 Cache Miss: Index \(identifier)") let index = Index(datastore: self, id: identifier) trackedIndexes[identifier] = WeakValue(index) - Task { await snapshot.persistence.cache(index) } + Task(name: "CodableDatastore.DiskPersistence.Datastore.index(for:).cache - Datastore: \(id)") { await snapshot.persistence.cache(index) } return index } func adopt(index: Index) { trackedIndexes[index.id] = WeakValue(index) - Task { await snapshot.persistence.cache(index) } + Task(name: "CodableDatastore.DiskPersistence.Datastore.adopt(index:).cache - Datastore: \(id)") { await snapshot.persistence.cache(index) } } func invalidate(_ identifier: Index.ID) { @@ -194,13 +194,13 @@ extension DiskPersistence.Datastore { // print("🤷 Cache Miss: Page \(identifier.page)") let page = Page(datastore: self, id: identifier) trackedPages[identifier.withoutManifest] = WeakValue(page) - Task { await snapshot.persistence.cache(page) } + Task(name: "CodableDatastore.DiskPersistence.Datastore.page(for:).cache - Datastore: \(id)") { await snapshot.persistence.cache(page) } return page } func adopt(page: Page) { trackedPages[page.id.withoutManifest] = WeakValue(page) - Task { await snapshot.persistence.cache(page) } + Task(name: "CodableDatastore.DiskPersistence.Datastore.adopt(page:).cache - Datastore: \(id)") { await snapshot.persistence.cache(page) } } func invalidate(_ identifier: Page.ID) { @@ -262,7 +262,7 @@ extension DiskPersistence.Datastore { nextObserverID += 1 observers[id] = observer observer.onTermination = { _ in - Task { + Task(name: "CodableDatastore.DiskPersistence.Datastore.register(observer:).onTermination - Datastore: \(self.id), Observer: \(id)") { await self.unregisterObserver(for: id) } } diff --git a/Sources/CodableDatastore/Persistence/Disk Persistence/Transaction/Transaction.swift b/Sources/CodableDatastore/Persistence/Disk Persistence/Transaction/Transaction.swift index 23b9dfa..6add351 100644 --- a/Sources/CodableDatastore/Persistence/Disk Persistence/Transaction/Transaction.swift +++ b/Sources/CodableDatastore/Persistence/Disk Persistence/Transaction/Transaction.swift @@ -56,8 +56,8 @@ extension DiskPersistence { self.options = options self.transactionIndex = transactionIndex - let workDidFinishPromise = Promise(name: "DiskPersistence.Transaction.workDidFinish - \"\(actionName ?? "")\"") - let transactionDidPersistPromise = Promise(name: "DiskPersistence.Transaction.transactionDidPersist - \"\(actionName ?? "")\"") + let workDidFinishPromise = Promise(name: "CodableDatastore.DiskPersistence.Transaction.init(...).workDidFinish - Action: \"\(actionName ?? "")\"") + let transactionDidPersistPromise = Promise(name: "CodableDatastore.DiskPersistence.Transaction.init(...).transactionDidPersist - Action: \"\(actionName ?? "")\"") self.workDidFinishResult = workDidFinishPromise.future self.transactionDidPersistResult = transactionDidPersistPromise.future @@ -107,7 +107,7 @@ extension DiskPersistence { /// Persist the work that was just completed to signal to the next transaction that it can start, but check for the requested timing option first. ``persist()`` takes care of signaling when the persistence is finished. if options.contains(.collateWrites) { /// If we are skipping immediate writes, kick off persistence in a separate task. - Task { + Task(name: "CodableDatastore.DiskPersistence.Transaction.run()") { try await self.persist() } } else {