Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task Cancellation #18

Closed
saniul opened this issue Feb 19, 2014 · 5 comments
Closed

Task Cancellation #18

saniul opened this issue Feb 19, 2014 · 5 comments

Comments

@saniul
Copy link
Contributor

saniul commented Feb 19, 2014

I was wondering, what is the intended approach to task cancellation?

BFTask only exposes methods for task consumption and continuation, while the cancellation is implemented through BFTaskCompletionSource (which actually just calls internal cancellation methods of BFTask).
There is no way to cancel a BFTask without having a reference to its completion source.

Does this mean that a task producer should keep a reference to all its long-running cancellable task completion sources and expose an interface for identifying and cancelling a specific task?

@darrinm
Copy link

darrinm commented Feb 20, 2014

I've been wondering the same thing. Thanks for asking.

@bklimt
Copy link
Contributor

bklimt commented Feb 21, 2014

It's generally bad design to keep track of the BFTaskCompletionSource for cancellation. For one, that introduces too many opportunities for the source to have its result or error set when you didn't want them to. But a bigger concern is that as you compose tasks together, you will often have one concept of a "cancelable operation" that's composed of several tasks chained together. For example, querying for a new object online might have multiple async subtasks for retrying or writing the results to a local file or database. And some high-level tasks may even share subtasks. You don't want cancellation one of the high-level tasks to cancel all of them.

So a better model is to create a "cancellation token" at the top level, and pass that to each async function that you want to be part of the same "cancelable operation". Then, in your continuation blocks, you can check whether the cancellation token has been cancelled and bail out early by returning a [BFTask cancelledTask].

We are likely to add some concept like this to Bolts at some point in the future. In the meantime, you can use an NSOperation simply as an implementation of an object that is thread-safe and has cancel and isCancelled method. :-) For example:

- (void)doSomethingComplicatedAsync:(NSOperation *)cancellationToken {
    [[self doSomethingAsync:cancellationToken] continueWithBlock:^{
        if (cancellationToken.isCancelled) {
            return [BFTask cancelledTask];
        }
        // Do something that takes a while.
        return result;
    }];
}

// Somewhere else.
NSOperation *cancellationToken = [[NSOperation alloc] init];
[obj doSomethingComplicatedAsync:cancellationToken];

// When you get bored...
[cancellationToken cancel];

@saniul
Copy link
Contributor Author

saniul commented Feb 21, 2014

Cool, thanks for advice!

I guess It might be a good idea to propose the cancellation token approach in the README?

@bklimt
Copy link
Contributor

bklimt commented Feb 21, 2014

Yeah, I think so. Feel free to open a pull request. ;-)

Or we will add it later.

@saniul
Copy link
Contributor Author

saniul commented Feb 21, 2014

Already on it.

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

No branches or pull requests

3 participants