Created
October 11, 2025 13:18
-
-
Save ertembiyik/80876683c5390f4b51ba652949b69441 to your computer and use it in GitHub Desktop.
KeyedTaskExecutor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Foundation | |
| fileprivate protocol CancellableOperation { | |
| func cancelOperation() | |
| } | |
| extension Task: CancellableOperation { | |
| fileprivate func cancelOperation() { | |
| self.cancel() | |
| } | |
| } | |
| final class KeyedTaskExecutor: @unchecked Sendable { | |
| #if compiler(>=6.0) | |
| typealias ThrowingOperation<Success> = @isolated(any) @Sendable () async throws -> sending Success | |
| typealias Operation<Success> = @isolated(any) @Sendable () async -> sending Success | |
| #else | |
| typealias ThrowingOperation<Success: Sendable> = @Sendable () async throws -> Success | |
| typealias Operation<Success: Sendable> = @Sendable () async -> Success | |
| #endif | |
| private var tasks: [String: CancellableOperation] = [:] | |
| private let lock = NSLock() | |
| func executeOperation<Success>(for key: String, | |
| @_inheritActorContext operation: @escaping Operation<Success>) async -> Success { | |
| let task = self.lock.withLock { | |
| if let existingTask = self.tasks[key] as? Task<Success, Never> { | |
| return existingTask | |
| } | |
| let newTask = Task<Success, Never> { | |
| return await operation() | |
| } | |
| self.tasks[key] = newTask | |
| return newTask | |
| } | |
| defer { | |
| self.lock.withLock { | |
| self.tasks[key] = nil | |
| } | |
| } | |
| return await task.value | |
| } | |
| func executeOperation<Success>(for key: String, | |
| @_inheritActorContext operation: @escaping ThrowingOperation<Success>) async throws -> Success { | |
| let task = self.lock.withLock { | |
| if let existingTask = self.tasks[key] as? Task<Success, Error> { | |
| return existingTask | |
| } | |
| let newTask = Task<Success, Error> { | |
| return try await operation() | |
| } | |
| self.tasks[key] = newTask | |
| return newTask | |
| } | |
| defer { | |
| self.lock.withLock { | |
| self.tasks[key] = nil | |
| } | |
| } | |
| return try await task.value | |
| } | |
| func cancelOperation(with key: String) { | |
| self.lock.withLock { | |
| self.tasks[key]?.cancelOperation() | |
| self.tasks[key] = nil | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
allows to execute only one task at a time for a given key by awaiting an existing one if present