Tobi
Tobi

Reputation: 183

Task Continuations strange behavior

I built a small chain of tasks with conditional continuations, however I'm experiencing some weired behavior. My chain looks like this:

LoadSettings (OnlyOnFaulted)-> ErrorHandler (none)-> Cleanup (none)-> Exit  
| (OnlyOnRanToCompletion)  
CheckForUpdates (OnlyOnFaulted)-> ErrorHandler (none)-> Cleanup (none)-> Exit  
| (OnlyOnRanToCompletion)  
Update (OnlyOnFaulted)-> ErrorHandler (none)-> Cleanup (none)-> Exit  
| (OnlyOnRanToCompletion)   
Cleanup  (OnlyOnFaulted)-> ErrorHandler (none)-> Exit  
| (OnlyOnRanToCompletion)   
Exit

As I understood this chain should run asynchronically (i.e. not in the ui thread) but one after another (so LoadSettings -> CheckForUpdates -> ...).
However I get this behavior:
LoadSettings -> CheckForUpdates -> Cleanup -> Exit -> Cleanup -> ... Also, the first Cleanup gets called with the Task id 1 as parameter (this is the task executed right before, right?) and this Task had the status Canceled (and I never cancel a Task anywhere).
Does anyone know what's going wrong here?

Edit: Ok, according to msdn if a condition for a continuation is not met its task get canceled. So ErrorHandler gets canceled, but how can I stop the complete chain (or notify the other continuations with cleanup and exit that it has been canceled)?

Upvotes: 1

Views: 90

Answers (2)

pkt
pkt

Reputation: 1838

Setting up the ErrorHandler -> Cleanup continuation as OnlyOnRanToCompletion or NotOnCanceled would work. Also, maybe you could simplify things a bit with async. Something like this could work:

try {
    var settings = await LoadSettings();
    var updatesNeeded = await CheckForUpdates(settings);
    await Update(updatesNeeded);
} catch (Exception e) {
    ErrorHandler(e);
} finally {
    Cleanup();
}

Note that the error handling and cleanup would be synchronous here, since you can't await in a catch/finally block. You could get around that by only storing the exception in a variable, which you later check for null and pass to the async error handler.

Upvotes: 0

usr
usr

Reputation: 171246

Using Task.WhenAny you can create a task that runs when either the success handler or the error handler have completed. Off of that task you continue with Cleanup.

It is sometimes tricky to set up the continuation chains right, but you can construct pretty complicated flow graphs using combinator functions like Task.WhenAny.

If you can use async/await the task simplifies a lot. You can then use normal control flow constructs. You can also simulate await using iterators.

Upvotes: 0

Related Questions