New Feature? :: Delayed cancellation

New Feature? :: Delayed cancellation

  • Comments 9

 

We’re interested in adding support for scheduling cancellation.  For example:

 

// Create a token source that will Cancel() after a delay
var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(100));


// And/or schedule a Cancel() call
cts.CancelAfter(TimeSpan.FromMilliseconds(100));


We’ve heard from many folks that this is a desired feature and have found good uses for it ourselves.  Interestingly, we would also allow CancelAfter() to be called multiple times to reset the delay (provided the token source was not already canceled, of course).  One could also effectively cancel the cancellation by calling CancelAfter() with TimeSpan.MaxValue.

 

One potential issue we’ve been thinking through is whether/how to deal with exceptions that fly out of user-registered delegates.  Recall that we strongly discourage throwing exceptions from callbacks registered with a CancellationToken, though it is possible to handle such exceptions today:

 

cts.Token.Register(() => { throw new Exception(“HA!”); });

try { cts.Cancel(); } // invokes the callbacks
catch { // Caught it! }


However, if you use this new feature to cancel asynchronously, you won’t ever have a chance to handle the exception, and it would likely bring down your application.  Some are of the opinion that we need not do anything about this, but we’ve been brainstorming potential solutions anyway.  We’re definitely curious what you think =).  Feel free to answer these questions if you want:

  1. What do you think about unhandled exceptions flying out of user-created token callbacks?  Should we support this use case?
  2. Any feedback about the general feature?

Thanks!

 

Leave a Comment
  • Please add 2 and 4 and type the answer here:
  • Post
  • I actually like the UnhandledException registration that you can do with windows forms.  At least it gives me a chance to try to more gracefully exit from a bad situation rather than going straight tot he dumper.  For example I can mark that particular callback as "suspect" and not load it again the next time my app runs.

    And to facilitate handling and catching exceptions, it would be really nice if the Code Analysis feature didn't complain so much about catching Exception everywhere.   Yes I can turn it off and no I don't have a clever idea about how to fix it BUT it causes needless debate in code reviews every time.

  • I like the CancelAfter() feature idea.  Being able to provide feedback to the UI would be useful for a situation like that though (especially if the cancel timer can be reset).  So the token should probably provide a way to determine the current cancel count-down progress.

  • Pardon my lack of familiarity with the TPL, I work primarily in C++.  But could you instead propogate the exception onto the cancelled task? Ie, if the user cancels a task using said token, capture that exception in the task and invoke the task's ContinueWith clauses.

  • aaron:

    There are three ways to respond to a cancellation:

    - You 'bind' it to a scheduled task. In this case this task won't be started.

    - You explicitly ask a token if it is canceled with IsCancellationRequested and ThrowIfCancellationRequested. You don't have to do this inside a task.

    - You register for an event that fires on cancellation.

    It's the third option that represents the problem.

    dashih:

    I'd say handle it the same way Timer handles an exception in the TimerCallback. I'm not sure though if you should continue executing other registrations and what should happen if multiple registrations throw. But then I'm not the one working as MS. ;-)

  • I think it should never be the case that any kind of async exeptions can't be caught and handled, even if they happend on a cancellation token callback.

    I can think of a few scenarios where cancellation can take a long time to finish. It can involve remote calls or time consumming rollback operations. In all cases handling cancellation exceptions might be very important to ensure the state of the application is not corrupted. I' thinking of nested transations here of any kind (even file system transactions).

    Basically withouth the option to handle cancellation exceptions, cancellation tokens cannot be used in scenarios where cancellation involves more than the very simple code, and also application state must be controled even in the face of cancellation exceptions.

    Example: an inner transaction cancelation token throws an exception durring cancellation, this means cancelation (rollback) has failed, and the application must also cancell the outer transation. In the event the cancellation exceptions can't be handled, the outer transaction will never get the chance to rollback, leading to corrupted state somewhere.

    My opinion is that "cts.Cancel()" should also return a "Task", which ofcourse is cancellable :), so the programming model is simetric.

  • You could provide additional overloads for cts' constructor & CancelAfter method, which accept an exception handler of type Func<Exception>, like this:

      void CancelAfter(TimeSpan timeout, Func<Exception> onError)

  • Hey dashih, Lots of good suggestions about how to implement this feature. Can you comment about the scenario's where people need this feature.

  • Lots of good suggestions about how to implement this feature. Hey dashih, can you comment about the scenario's where people need this feature. Thanks.

  • Thanks All for your feedback!

    Re: use cases [@Faisal Mansoor]

    The feature is kind of just generally useful whenever you need to cancel something after a time delay.  For example, in one of our demos (a Reversi game), delayed cancellation tokens could be used to timebox the Minimax algorithms (which would search the game tree until a token was set).

    In addition, if you're going to have a lot of these things active, it becomes crucial to clean up underlying resources (e.g. Timer objects) as soon as they are no longer needed.  Similarly, if a token source is manually canceled before the delayed cancel operation, you could achieve better performance by preventing the timer's delegate from even executing.  Addressing these issues with a handrolled implementation can actually get pretty tricky.

    Re: CancelAfter(..., Func<Exception> onError) [@Omer Mor]

    Yup, this is definitely a viable solution.  The bigger question is still whether this use case is something we want to support/prioritize or not.

Page 1 of 1 (9 items)