Task.Delay Challenge

2017/04/14

no comments

Task.Delay Challenge

Task.Delay can be useful in many scenarios, for example: periodic execution.

 Traditionally periodic execution done by using Timer API.

Periodic execution with Task.Delay is easy for debug and better for maintain.

The following code show the pattern:

Code Snippet
  1. private async Task PeriodicJobAsync(CancellationToken token)
  2. {
  3.     var duration = TimeSpan.FromSeconds(5);
  4.     while (!token.IsCancellationRequested)
  5.     {
  6.         try
  7.         {
  8.             await Task.Delay(duration, token);
  9.         }
  10.         catch (OperationCanceledException) { }
  11.  
  12.         // Process the job
  13.     }
  14. }

The problem start when you want to test the code without waiting the real-world duration.

Parallel, Rx, Delay, Pattern, Task, IObservable, async, await

 

The challenge is to write the alternative code which will be test friendly.

In order to do it you should use IScheduler for controlling the virtual time and pass the following tests.

Code Snippet
  1. [TestClass]
  2. public class TaskDelayChallengeTests
  3. {
  4.     private readonly TestScheduler _scheduler = new TestScheduler();
  5.  
  6.     [TestMethod]
  7.     public void VirtualDelayTest()
  8.     {
  9.         var midDuration = TimeSpan.FromSeconds(5);
  10.         var duration = TimeSpan.FromSeconds(10);
  11.         Task execution = UnitUnderTest(duration, CancellationToken.None);
  12.         Assert.IsFalse(execution.IsCompleted);
  13.         _scheduler.AdvanceTo(midDuration.Ticks);
  14.         Assert.IsFalse(execution.IsCompleted);
  15.         _scheduler.AdvanceTo(duration.Ticks);
  16.         Assert.IsTrue(execution.IsCompleted);
  17.     }
  18.  
  19.     [TestMethod]
  20.     public void CancelDelayTest()
  21.     {
  22.         var cts = new CancellationTokenSource();
  23.         var duration = TimeSpan.FromSeconds(10);
  24.         Task execution = UnitUnderTest(duration, cts.Token);
  25.         Assert.IsFalse(execution.IsCompleted);
  26.         cts.Cancel();
  27.         Assert.IsTrue(execution.IsCompleted);
  28.     }
  29.  
  30.     private async Task UnitUnderTest(TimeSpan duration, CancellationToken token)
  31.     {
  32.         // TODO: replace the following line with implementation that
  33.         //       respect the scheduler (_scheduler)
  34.         await Task.Delay(duration, token);
  35.     }
  36. }

 

Quick access to previous challenges can be found at this link.

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*