我们有一个逻辑,可以让后台作业每20分钟运行一次,或者在完成任务后继续运行。
我想做的简化版如下:
控制是否需要退出的任务:
private static TaskCompletionSource<bool> forceSyncTask = new TaskCompletionSource<bool>();
后台工作:
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);
});
然后每当有通知到来时,我运行以下命令强制退出Task.WhenAny
if (!forceSyncTask.Task.IsCompleted)
{
forceSyncTask.TrySetResult(true);
}
我在开发框中对其进行了测试,并且可以正常工作。但是,在将其部署到产品环境中的Webervice之后,即使我成功完成SetResult(我已记录下来知道TrySetResult是否返回true),Task.WhenAny也不会按预期退出。
任何人都知道为什么吗?
首先,我建议您使用已建立的解决方案来暂停异步方法,例如Stephen Toub's PauseToken
或PauseToken
。当前代码中有一些危险信号:PauseToken
from my AsyncEx library,并且不带PauseToken
选项的情况下使用StartNew
with an async
delegate and without a TaskScheduler
。最好坚持使用较高级别的结构(分别为StartNew
和async
),因为低级结构上有很多尖角。
就确切的问题而言,这很难说,特别是因为您(和我们)无法在本地复制它。这是我的最高猜测:
TaskScheduler
-即TaskCompletionSource<T>
最终直接调用RunContinuationsAsynchronously
中的某些代码而导致的问题。