×

Welcome to TagMyCode

Please login or create account to add a snippet.
0
0
 
0
Language: C#
Posted by: Tobias Richter
Added: Apr 21, 2016 1:35 PM
Modified: May 9, 2016 6:09 AM
Views: 13
Set timeout for a specific method. Useful for example calling 3rd party products which doesn't timeout after a certain time.
  1. // Example class using OperationWithTimeout
  2. public class ConvertHelper
  3. {
  4.     public static byte[] ConvertWordToPdf(Stream inputStream)
  5.     {
  6.         var operationWithTimeout = new OperationWithTimeout();
  7.         TimeSpan timeout = TimeSpan.FromSeconds(30); // Timeout after 30 seconds if operation isn't done (seems like SaveToStream contains a while-loop)
  8.  
  9.         Func<CancellationToken, byte[]> operation = token =>
  10.         {
  11.             // Enter your code here
  12.             using (var ms = new MemoryStream())
  13.             {
  14.                 Document doc = new Document();
  15.                 doc.LoadFromStream(inputStream, FileFormat.Auto);
  16.                 doc.SaveToStream(ms, FileFormat.PDF);
  17.                 doc.Close();
  18.                 return ms.ToArray();
  19.             }
  20.         };
  21.  
  22.         var task = operationWithTimeout.Execute<byte[]>(operation, timeout);
  23.         var result = task.Result;
  24.  
  25.         return result;
  26.     }
  27. }
  28.  
  29.  
  30. // OperationWithTimeout
  31. public class OperationWithTimeout
  32. {
  33.     public Task<T> Execute<T>(Func<CancellationToken, T> operation, TimeSpan timeout)
  34.     {
  35.         var cancellationToken = new CancellationTokenSource();
  36.  
  37.         // Two tasks are created.
  38.         // One which starts the requested operation and second which starts Timer.
  39.         // Timer is set to AutoReset = false so it runs only once after given 'delayTime'.
  40.         // When this 'delayTime' has elapsed then TaskCompletionSource.TrySetResult() method is executed.
  41.         // This method attempts to transition the 'delayTask' into the RanToCompletion state.
  42.         Task<T> operationTask = Task<T>.Factory.StartNew(() => operation(cancellationToken.Token), cancellationToken.Token);
  43.         Task delayTask = Delay(timeout.TotalMilliseconds);
  44.  
  45.         // Then WaitAny() waits for any of the provided task objects to complete execution.
  46.         Task[] tasks = new Task[] { operationTask, delayTask };
  47.         Task.WaitAny(tasks);
  48.  
  49.         try
  50.         {
  51.             if (!operationTask.IsCompleted)
  52.             {
  53.                 // If operation task didn't finish within given timeout call Cancel() on token and throw 'TimeoutException' exception.
  54.                 // If Cancel() was called then in the operation itself the property 'IsCancellationRequested' will be equal to 'true'.
  55.                 cancellationToken.Cancel();
  56.                 throw new TimeoutException("Timeout waiting for method after " + timeout + ". Method was to slow :-)");
  57.             }
  58.         }
  59.         finally
  60.         {
  61.             cancellationToken.Dispose();
  62.         }
  63.  
  64.         return operationTask;
  65.     }
  66.  
  67.     public static Task Delay(double delayTime)
  68.     {
  69.         var completionSource = new TaskCompletionSource<bool>();
  70.         System.Timers.Timer timer = new System.Timers.Timer();
  71.         timer.Elapsed += (obj, args) => completionSource.TrySetResult(true);
  72.         timer.Interval = delayTime;
  73.         timer.AutoReset = false;
  74.         timer.Start();
  75.         return completionSource.Task;
  76.     }
  77. }