Closed SaadArdati closed 10 months ago
Hello,
Unfortunately ValueTasks cannot be truely cancelled. Cancelling a ValueTask will throw a CancelledException
in the calling Isolate, but the worker Isolate will continue executing the task until it completes. This is by design because of Dart's execution model: once a synchronous block of code has been scheduled in the Isolate's event loop and starts running, it will run uninterrupted until it completes. Note that if the ValueTask is still pending in Squadron's internal queue, it will be cancelled straight away and will never be handed over to the worker Isolate.
A few tips about effectively cancelling a synchronous task is to make it asynchronous and make sure the service method accepts a CancellationToken
argument. The service method must periodically check the CancellationToken.cancelled
property and if true, stop processing. The calling Isolate will still receive a CancelledException
so your code should take action and handle the case when a task is cancelled.
Eg. if the (uncancellable) synchronous task looks like this:
@squadronMethod
FutureOr<int> computeSync(Uint8List input) {
var value = 0;
for (var i = 0; i < bigNumber; i++) {
// update value
}
return value;
}
It can be turned into a cancellable task like so:
@squadronMethod
Future<int> computeSync(Uint8List input, { CancellationToken? cancelToken }) async {
var value = 0;
for (var i = 0; i < bigNumber; i++) {
if (cancelToken != null && i % 500 == 0) {
await Future.delayed(Duration.zero); // necessary to ensure the cancelToken state is updated
if (cancelToken.cancelled) {
return -1;
}
}
// update value
}
return value;
}
Now in your specific context, I believe this is not feasible because fuzzy.search()
is synchronous and uncancellable. Debouncing will certainly help by avoiding submitting unnecessary tasks to the worker. I think you should also use the limit
argument to avoid full scans. It will also make the call to sublist
useless so you can directly return the results.
This is excellent advise, thank you!
I'm trying to implement a heavy json search that utilizes the Fuzzy package to do a string search on a large json object (~90mb). When typing a search query, I could normally debounce the input, but even then, a singular search task takes seconds to resolve.
I understand that ValueTasks or non-stream-based tasks are not effectively cancellable, is this correct? Is there a way around this for my use case?
Here's a log output:
Each search operation is taking ~3-5 seconds each. This is of course a worse-case scenario where the search query is not debounced at all, but this is for testing purposes.
The cancelling doesn't work like I expect it to so I'm curious if there is a solution I'm not aware of.