-
-
Notifications
You must be signed in to change notification settings - Fork 7
Task Cancellation
Squadron provides flexible mechanisms to cancel tasks, whether they are waiting in a queue or currently executing.
Depending on your needs (canceling a specific calculation, managing queue load, or implementing timeouts), you can choose between Cooperative Cancellation (using Tokens) or Task Management (using Pool APIs).
This is the most robust way to handle cancellation, especially for CPU-intensive tasks. It ensures that the worker thread actually stops working, freeing resources for other tasks.
It relies on passing a CancelationToken (from package:cancelation_token) to your service method. The worker code periodically checks this token and throws an exception if cancellation is requested.
Update your service method to accept a CancellationToken.
@SquadronMethod()
Future<void> heavyProcess(Data data, [CancellationToken? token]) async {
for (var i = 0; i < 1000; i++) {
// 1. Check if cancelation was requested
// If canceled, this throws a CanceledException immediately
token?.throwIfCanceled();
// 2. Perform a chunk of work
await performStep(i);
}
}Create a token, pass it to the worker, and cancel it when needed.
// 1. Create a token source
final token = CancelableToken();
try {
// 2. Pass the token to the worker
// Squadron handles the cross-thread signaling automatically
final future = worker.heavyProcess(myData, token);
// ... let's say user navigates away ...
token.cancel(); // 3. Sends signal to worker
await future;
} on CanceledException {
print('Task was canceled successfully!');
}-
TimeoutToken: Automatically cancels itself after a duration.// Cancel automatically after 5 seconds final token = TimeoutToken(Duration(seconds: 5)); worker.heavyProcess(data, token);
-
CompositeToken: Combines multiple tokens.final userToken = CancelableToken(); final timeoutToken = TimeoutToken(Duration(seconds: 30)); // Cancels if USER cancels OR timeout expires final combo = CompositeToken.any([userToken, timeoutToken]);
When using a WorkerPool, you have additional controls to manage the task queue directly on the main thread.
Cancels a specific task.
final task = pool.scheduleValueTask((w) => w.heavyProcess(data));
// Later...
pool.cancel(task, "User aborted");Clears the entire queue and attempts to cancel all running tasks.
// Emergency stop or clearing state
pool.cancelAll("Resetting application");The behavior of pool.cancel(task) depends entirely on the state of the task:
-
Pending Tasks (In Queue):
- Effect: The task is removed from the queue. It is never sent to a worker.
- Result: This is instant and safe.
-
Running Tasks (value tasks like
Future<T>):-
Effect: The
Futureon the main thread is completed immediately with aCanceledException. -
The Trap: If you did NOT use a
CancelationToken, the worker thread keeps running until it finishes the computation. It has no way to know the main thread isn't listening anymore. The result is simply discarded when it arrives. -
Solution: Always use a
CancelationTokenif the task is long-running, so the worker can actually stop.
-
Effect: The
-
Running Streams (stream tasks like
Stream<T>):- Effect: Squadron sends a control cancellation message to the worker.
- Result: The generator function in the worker will stop being pulled (producer stops) and the stream closes. This effectively stops the worker.
| Feature | token.cancel() |
pool.cancel(task) |
|---|---|---|
| Primary Use Case | Stopping work (CPU/IO) | Managing User Experience / Queue |
| Effect on Worker | Stops execution (frees thread) | Detaches listener (thread might stay busy) |
| Stream Support | Yes | Yes (Auto-closes stream) |
| Timeout Support | Yes via TimeoutToken
|
Manual management required |
-
Use
CancelableTokenwhenever you have a long-running CPU task. This is the only way to stop a running CPU task and reclaim the worker for other jobs. -
Check
token.throwIfCanceled()frequently in your service loops. -
Use
pool.cancel()when you need to clear a backlog of pending items (e.g., user changed filters and previous requests are obsolete).
💖 Support the project! Sponsor d-markey on GitHub.