Skip to content

Conversation

@dfed
Copy link
Owner

@dfed dfed commented Nov 28, 2025

Addresses #62 by creating a new CancellableQueue type that wraps either FIFOQueue or ActorQueue and allows tasks enqueued on the cancellable queue to be cancelled.

I created a separate queue type to avoid making every FIFOQueue and ActorQueue create yet another queue – this feels like a specialized use case, and so a specialized queue type seemed like a reasonable solution.

@codecov
Copy link

codecov bot commented Nov 28, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (09c6dda) to head (d99703f).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##              main       #63    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files           11        13     +2     
  Lines         1015      1293   +278     
==========================================
+ Hits          1015      1293   +278     
Files with missing lines Coverage Δ
Sources/AsyncQueue/CancellableQueue.swift 100.00% <100.00%> (ø)
Sources/AsyncQueue/FIFOQueue.swift 100.00% <ø> (ø)
Tests/AsyncQueueTests/CancellableQueueTests.swift 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dfed dfed force-pushed the dfed--cancellation branch from d7ee222 to 3ec737f Compare November 28, 2025 17:51
@dfed dfed linked an issue Nov 28, 2025 that may be closed by this pull request
// MARK: Public

/// Cancels the currently executing task, as well as any task currently pending in the queue.
public func cancelTasks() {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cancelAll is a reasonable name too. I like cancelTasks a little bit better because it doesn't imply that future tasks will be cancelled as well.

dfed and others added 2 commits November 28, 2025 12:35
* Ignore agent configuration

* Add CancellableQueueTests for 100% test coverage

Test cancelTasks() behavior across all queue types:
- FIFOQueue (with isolated and throwing variants)
- ActorQueue
- MainActor queue

Each queue type tests four scenarios:
- doesNotCancelCompletedTask
- cancelsCurrentlyExecutingTask
- cancelsCurrentlyExecutingAndPendingTasks
- doesNotCancelFutureTasks

* Use semaphores instead of sleep for test synchronization

Replace brittle Task.sleep timing with proper semaphore-based
synchronization to ensure tasks have started before cancellation.

* Simplify tests by returning Task.isCancelled directly

Remove Expectation usage in favor of checking task.value directly.
This eliminates timeouts and makes tests cleaner.

* Use task.isCancelled property instead of returning from closure

Check cancellation status directly on the Task instance rather than
returning Task.isCancelled from within the closure.

* Remove unnecessary task awaits

Check task.isCancelled immediately after cancelTasks() without
waiting for task completion. Only await task.result where needed
to ensure task completes before calling cancelTasks().

* Fix some of the 'didn't wait long enough' problem

* Add taskAllowedToEnd semaphore to ActorQueue and MainActor tests

Ensure tasks are still executing when cancelTasks() is called by
having them wait on a semaphore that is signaled after cancellation.

* Fix misleading comments about ActorQueue task ordering

ActorQueues are re-entrant, not FIFO, so tasks don't wait for
earlier tasks to complete.

* Fix flaky ActorQueue and MainActor cancellation tests

ActorQueues are re-entrant, so task2 and task3 would complete
immediately when task1 suspends, potentially before cancelTasks()
is called. Now all three tasks signal when started and wait on
semaphores, ensuring they're all still executing when cancelled.

* Rename ActorQueue/MainActor tests to reflect concurrent execution

ActorQueues are re-entrant, so tasks execute concurrently rather than
pending. Renamed tests from 'cancelsCurrentlyExecutingAndPendingTasks'
to 'cancelsAllConcurrentlyExecutingTasks' to accurately describe behavior.

* Revert "Rename ActorQueue/MainActor tests to reflect concurrent execution"

This reverts commit 88f7fd0.

* mark

* formatting

* Simplify ActorQueue and MainActor multi-task cancellation tests

We only need to wait for task1 to start. Whether task2 and task3
are pending or already executing when cancelTasks() is called,
they will be cancelled either way.

* Ensure task2 and task3 wait before cancelTasks() is called

Tasks need to wait on the semaphore to ensure they haven't completed
and been removed from the cancel map before cancelTasks() is called.

* Ensure task3 is pending in ActorQueue/MainActor cancellation tests

Task2 now spins with try Task.checkCancellation() without suspension
points, preventing task3 from starting on the re-entrant queue. This
guarantees task3 is truly pending when cancelTasks() is called.

---------

Co-authored-by: Claude <noreply@anthropic.com>
dfed and others added 3 commits November 28, 2025 12:47
* Improve CancellableQueue documentation

- Expand class-level doc comment to explain behavior
- Add missing priority parameter documentation
- Fix "priority of the queue" typo (should be "priority of the task")
- Add CancellableQueue section to README with usage examples

* Apply suggestions from code review

---------

Co-authored-by: Claude <noreply@anthropic.com>
@dfed dfed marked this pull request as ready for review November 28, 2025 23:08
@dfed dfed merged commit afbf677 into main Nov 29, 2025
14 checks passed
@dfed dfed deleted the dfed--cancellation branch November 29, 2025 05:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proposal: Add cancelAll() method to FIFOQueue/ActorQueue

2 participants