Last active
July 28, 2024 10:09
-
-
Save egzonpllana/8857710a23ad8316e6896a7c2be5f48f to your computer and use it in GitHub Desktop.
Service to manage repeated execution of tasks at specified intervals.
This file contains 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 | |
/// Protocol defining the behavior of a repeated task service. | |
protocol RepeatedTaskServiceProtocol { | |
/// Schedules a repeated task to be executed at specified intervals. | |
/// - Parameters: | |
/// - interval: The time interval between executions. | |
/// - repeatCount: The number of times to repeat the task. | |
/// - identifier: The optional unique identifier for the task. If nil, an identifier will be auto-generated. | |
func execute( | |
every interval: TimeInterval, | |
repeatCount: Int, | |
withIdentifier identifier: String?, | |
task: @Sendable @escaping () -> Void | |
) throws | |
/// Stops a task with the specified identifier. | |
/// - Parameter identifier: The unique identifier for the task. | |
func stopTask(withIdentifier identifier: String) | |
/// Stops all currently scheduled tasks. | |
func stopAllTasks() | |
/// Stops all tasks without explicit identifiers. | |
func stopTasksWithoutIdentifiers() | |
} | |
extension RepeatedTaskServiceProtocol { | |
/// Schedules a repeated task to be executed at specified intervals without an identifier. | |
/// - Parameters: | |
/// - interval: The time interval between executions. | |
/// - repeatCount: The number of times to repeat the task. | |
/// - task: The task to be executed. | |
func execute(every interval: TimeInterval, repeatCount: Int, task: @Sendable @escaping () -> Void) throws { | |
try execute(every: interval, repeatCount: repeatCount, withIdentifier: nil, task: task) | |
} | |
} | |
enum RepeatedTaskServiceError: Error { | |
case identifierAlreadyInUse | |
} | |
/// Service to manage repeated execution of tasks at specified intervals. | |
final class RepeatedTaskService: RepeatedTaskServiceProtocol { | |
private var tasks: [String: (task: DispatchWorkItem, isAutoGenerated: Bool)] = [:] | |
private let queue = DispatchQueue(label: "RepeatedTaskServiceQueue") | |
private var identifierCounter = 0 | |
init() { } | |
/// Schedules a repeated task to be executed at specified intervals. | |
/// - Parameters: | |
/// - interval: The time interval between executions. | |
/// - repeatCount: The number of times to repeat the task. | |
/// - task: The task to be executed. | |
/// - identifier: The optional unique identifier for the task. If nil, an identifier will be auto-generated. | |
func execute( | |
every interval: TimeInterval, | |
repeatCount: Int, | |
withIdentifier identifier: String?, | |
task: @Sendable @escaping () -> Void | |
) throws { | |
// Check if the identifier is auto-generated | |
let isAutoGenerated = identifier == nil | |
// Generate a unique identifier if not provided | |
let taskIdentifier = identifier ?? generateUniqueIdentifier() | |
// Check if the identifier is already in use | |
guard tasks[taskIdentifier] == nil else { | |
throw RepeatedTaskServiceError.identifierAlreadyInUse | |
} | |
// Create a new DispatchWorkItem to execute the task repeatedly | |
let newTask = DispatchWorkItem { | |
for _ in 0..<repeatCount { | |
// Execute the task | |
task() | |
// Sleep for the specified interval before the next execution | |
Thread.sleep(forTimeInterval: interval) | |
} | |
} | |
// Store the task with its identifier | |
self.tasks[taskIdentifier] = (task: newTask, isAutoGenerated: isAutoGenerated) | |
// Perform the following actions asynchronously on the queue | |
queue.async { | |
// Execute the task on a background queue | |
DispatchQueue.global(qos: .background).async(execute: newTask) | |
} | |
} | |
/// Stops a task with the specified identifier. | |
/// - Parameter identifier: The unique identifier for the task. | |
func stopTask(withIdentifier identifier: String) { | |
queue.async { | |
guard let task = self.tasks[identifier] else { return } | |
task.task.cancel() | |
self.tasks.removeValue(forKey: identifier) | |
} | |
} | |
/// Stops all currently scheduled tasks. | |
func stopAllTasks() { | |
queue.async { | |
self.tasks.forEach { $0.value.task.cancel() } | |
self.tasks.removeAll() | |
} | |
} | |
/// Stops all tasks without explicit identifiers. | |
func stopTasksWithoutIdentifiers() { | |
queue.async { | |
self.tasks.filter { $0.value.isAutoGenerated }.forEach { $0.value.task.cancel() } | |
self.tasks = self.tasks.filter { !$0.value.isAutoGenerated } | |
} | |
} | |
private func generateUniqueIdentifier() -> String { | |
UUID().uuidString | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment