Cancel a Thread.Sleep uh Task.Delay the right way

To wait, or not to waitIn one of my Windows Azure Workers I’m using a back-off algorithm to expand the time between checking the queue for new messages. In my solution the time between checks can become as large as 5 minutes. While that helps in making sure I’m not creating unnecessary data transactions and limit the cpu-usage, it won’t help me when I’m deploying a new update. When a new deployment is done the old-running deployment will be gracefully shutdown. Meaning it waits until all processes are done. In the case of a sleep of 5 minutes, it will wait until it’s ready with that sleep instead of cancelling that sleeping. I thought that to be strange, so I was looking into a nice solution.

The solution is easy as long as you have a CancellationToken available to pass to the Task.Delay method. You can create a CancellationToken by using the CancellationTokenSource. I’ve always been using the overload that just takes one argument, but the overload that takes two arguments allows cancellation. The below sample application explains how to use it.

internal class Program
{
    private static void Main(string[] args)
    {
        var tokenSource = new CancellationTokenSource();
        Task consoleReadTask = Task.Run(
            () =>
                {
                    Console.WriteLine("Press the enter key to cancel execution of tasks.");
                    Console.ReadLine();
                    tokenSource.Cancel();
                });

        Task workerTask = Task.Run(
            async () =>
                        {
                            CancellationToken token = tokenSource.Token;
                            try
                            {
                                while (!token.IsCancellationRequested)
                                {
                                    Console.WriteLine("Task output @ {0}", DateTime.Now);
                                    await Task.Delay(60000, token);
                                }
                            }
                            catch (OperationCanceledException)
                            {
                                Console.WriteLine("Cancelled @ {0}", DateTime.Now);
                            }
                        });

        Task.WaitAll(consoleReadTask, workerTask);
        Console.WriteLine("Press the enter key to exit.");
        Console.ReadLine();
    }
}
Gravatar