简体   繁体   中英

Task.WhenAny does not exist when task is finished

We have a logic for a background job to keep running, either every 20 minuts, or when a task if finished.

A simplified version of what I want to do is as followed:

Task to control if we need to exit:

private static TaskCompletionSource<bool> forceSyncTask = new TaskCompletionSource<bool>();

Background job:

     Task.Factory.StartNew(
                async () =>
                {
                    do
                    {
                        await Dosomething();
                        await Task.WhenAny(Task.Delay(TimeSpan.FromMinutes(20)), forceSyncTask.Task);

                        // Always reset the force sync property
                        forceSyncTask = new TaskCompletionSource<bool>();
                    }
                    while (true);
                });

Then everytime there is a notification comes, I run the following to force to exit the Task.WhenAny

    if (!forceSyncTask.Task.IsCompleted)
    {
        forceSyncTask.TrySetResult(true);
    }

I tested it in dev box and it works. However after I deployed it to our webervice in prod environment, even if I successfully SetResult (I have logging to know if TrySetResult returns true or not), the Task.WhenAny does not exit as expected.

Anyone has any idea why?

First, I recommend you use an established solution for pausing asynchronous methods, such as Stephen Toub's PauseToken or the PauseToken from my AsyncEx library . There's some red flags in the code as it currently stands: StartNew with an async delegate and without a TaskScheduler , and TaskCompletionSource<T> being used without the RunContinuationsAsynchronously option. It's better to stick to higher-level constructs ( Task.Run and PauseToken , respectively) because there are lots of sharp corners on the low-level constructs.

As far as what exactly the problem is, that's difficult to tell, especially since you (and we) cannot reproduce it locally. Here's my top guesses:

  1. You're running into a problem caused by the fact that continuations run synchronously if possible - ie, TrySetResult ends up directly invoking some code within Task.WhenAny .
  2. You're experiencing thread exhaustion on your production server.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM