I have a method that registers a background task that looks like this:
//snippet from task builder method
try
{
cancellationTokenSource.CancelAfter(10000);
btr = Task.Run(() => registerTask(builder, btr,cancellationTokenSource.Token), cancellationTokenSource.Token).Result;
}
catch (OperationCanceledException) // something went wrong
{
return null;
}
private BackgroundTaskRegistration registerTask(BackgroundTaskBuilder builder, BackgroundTaskRegistration btr, CancellationToken token)
{
CancellationTokenSource newToken = new CancellationTokenSource();
Task cancelledCheck = Task.Run(() =>
{
while (true)
{
if (token.IsCancellationRequested)
{
newToken.Cancel();
token.ThrowIfCancellationRequested();
}
}
}, newToken.Token);
btr = Task.Run(()=> builder.Register(),token).Result;
return btr;
}
My issue is that sometimes the builder.Register() method does not return anything. It's probably a Windows bug of some sort; the Register() method never finishes internally. Indeed, after 10 seconds, the token.ThrowIfCancellationRequested() method is called, but it does not throw to the try-catch statement where it's called. Initially I was calling builder.Register() directly without a Task.Run() but it didn't work, and neither does this.
However, if I replace btr = Task.Run(() =>...
with a Task.Delay(ms)
instead, where ms > 10000
, my intended effect happens.
Am I doing something wrong? Or is there a better way to do this? Basically I just need code that will make the registerTask() method return null when builder.Register() does not finish after a few seconds.
Replacing the code with something like this worked for me:
btr = null;
cancellationTokenSource.CancelAfter(10000);
Task registerTask = Task.Factory.StartNew(() =>
{
btr = builder.Register();
});
Task cancellationTask = Task.Factory.StartNew(() =>
{
while (true)
{
if (cancellationTokenSource.Token.IsCancellationRequested) break;
}
}, cancellationTokenSource.Token);
Task[] tasks = new Task[2] { cancellationTask, registerTask };
Task.WaitAny(tasks);
Instead of handling the error, getting a cancellation request will trigger one of the tasks to end, and when it ends I return the task registration variable whether it's null or not.