Skip to content

Commit 8112854

Browse files
committed
Don’t start executing a task when cancelToBeRescheduled is called before execute
`QueuedTask.execute` is called from a detached task in `TaskScheduler.poke` but we insert it into the `currentlyExecutingTasks` queue beforehand. This left a short windows in which we could cancel the task to reschedule it before it actually started executing. Change `QueuedTask` to just return immediately from `execute` if it has been cancelled to be rescheduled beforehand.
1 parent 42e4342 commit 8112854

File tree

1 file changed

+10
-1
lines changed

1 file changed

+10
-1
lines changed

Sources/SKCore/TaskScheduler.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,15 @@ public actor QueuedTask<TaskDescription: TaskDescriptionProtocol> {
228228
/// Execution might be canceled to be rescheduled, in which case this returns `.cancelledToBeRescheduled`. In that
229229
/// case the `TaskScheduler` is expected to call `execute` again.
230230
func execute() async -> ExecutionTaskFinishStatus {
231+
if cancelledToBeRescheduled {
232+
// `QueuedTask.execute` is called from a detached task in `TaskScheduler.poke` but we insert it into the
233+
// `currentlyExecutingTasks` queue beforehand. This leaves a short windows in which we could cancel the task to
234+
// reschedule it before it actually starts executing.
235+
// If this happens, we don't have to do anything in `execute` and can immediately return. `execute` will be called
236+
// again when the task gets rescheduled.
237+
cancelledToBeRescheduled = false
238+
return .cancelledToBeRescheduled
239+
}
231240
precondition(executionTask == nil, "Task started twice")
232241
let task = Task.detached(priority: self.priority) {
233242
if !Task.isCancelled && !self.resultTaskCancelled.value {
@@ -260,10 +269,10 @@ public actor QueuedTask<TaskDescription: TaskDescriptionProtocol> {
260269
///
261270
/// If the task has not been started yet or has already finished execution, this is a no-op.
262271
func cancelToBeRescheduled() {
272+
self.cancelledToBeRescheduled = true
263273
guard let executionTask else {
264274
return
265275
}
266-
self.cancelledToBeRescheduled = true
267276
executionTask.cancel()
268277
self.executionTask = nil
269278
}

0 commit comments

Comments
 (0)