Skip to main content
Code Review

Return to Question

replaced http://stackoverflow.com/ with https://stackoverflow.com/
Source Link

I've written an asynchronous retry method as an answer for this question this question. I'd like to get your opinion of the implementation and whether there are better ways to implement this. You could also implement this with async-await but I thought this would be a more efficient implementation.

public static Task RetryAsync(Func<bool> retryFunc, CancellationToken cancellationToken, int retryInterval)
{
 var tcs = new TaskCompletionSource<object>();
 var timer = new Timer((state) =>
 {
 var taskCompletionSource = (TaskCompletionSource<object>)state;
 if (!taskCompletionSource.Task.IsCompleted)
 {
 try
 {
 if (cancellationToken.IsCancellationRequested)
 {
 taskCompletionSource.SetException(new TaskCanceledException("RetryAsync cancelled"));
 }
 else if (retryFunc())
 {
 taskCompletionSource.SetResult(null);
 }
 }
 catch (Exception ex)
 {
 taskCompletionSource.SetException(ex);
 }
 }
 }, tcs, 0, retryInterval);
 
 //// Once the task is complete, dispose of the timer so it doesn't keep firing.
 tcs.Task.ContinueWith(t => timer.Dispose(),
 CancellationToken.None,
 TaskContinuationOptions.ExecuteSynchronously,
 TaskScheduler.Default);
 return tcs.Task;
}

I've written an asynchronous retry method as an answer for this question. I'd like to get your opinion of the implementation and whether there are better ways to implement this. You could also implement this with async-await but I thought this would be a more efficient implementation.

public static Task RetryAsync(Func<bool> retryFunc, CancellationToken cancellationToken, int retryInterval)
{
 var tcs = new TaskCompletionSource<object>();
 var timer = new Timer((state) =>
 {
 var taskCompletionSource = (TaskCompletionSource<object>)state;
 if (!taskCompletionSource.Task.IsCompleted)
 {
 try
 {
 if (cancellationToken.IsCancellationRequested)
 {
 taskCompletionSource.SetException(new TaskCanceledException("RetryAsync cancelled"));
 }
 else if (retryFunc())
 {
 taskCompletionSource.SetResult(null);
 }
 }
 catch (Exception ex)
 {
 taskCompletionSource.SetException(ex);
 }
 }
 }, tcs, 0, retryInterval);
 
 //// Once the task is complete, dispose of the timer so it doesn't keep firing.
 tcs.Task.ContinueWith(t => timer.Dispose(),
 CancellationToken.None,
 TaskContinuationOptions.ExecuteSynchronously,
 TaskScheduler.Default);
 return tcs.Task;
}

I've written an asynchronous retry method as an answer for this question. I'd like to get your opinion of the implementation and whether there are better ways to implement this. You could also implement this with async-await but I thought this would be a more efficient implementation.

public static Task RetryAsync(Func<bool> retryFunc, CancellationToken cancellationToken, int retryInterval)
{
 var tcs = new TaskCompletionSource<object>();
 var timer = new Timer((state) =>
 {
 var taskCompletionSource = (TaskCompletionSource<object>)state;
 if (!taskCompletionSource.Task.IsCompleted)
 {
 try
 {
 if (cancellationToken.IsCancellationRequested)
 {
 taskCompletionSource.SetException(new TaskCanceledException("RetryAsync cancelled"));
 }
 else if (retryFunc())
 {
 taskCompletionSource.SetResult(null);
 }
 }
 catch (Exception ex)
 {
 taskCompletionSource.SetException(ex);
 }
 }
 }, tcs, 0, retryInterval);
 
 //// Once the task is complete, dispose of the timer so it doesn't keep firing.
 tcs.Task.ContinueWith(t => timer.Dispose(),
 CancellationToken.None,
 TaskContinuationOptions.ExecuteSynchronously,
 TaskScheduler.Default);
 return tcs.Task;
}
deleted 1683 characters in body
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

Update

I updated the code as per @svick's comments. Here is the new version. Working to add overloads for processing of asynchronous retry functions.

 public static Task RetryAsync(Func<bool> retryFunc, TimeSpan retryInterval)
 {
 return RetryAsync(retryFunc, retryInterval, CancellationToken.None);
 }
 public static Task RetryAsync(Func<bool> retryFunc, TimeSpan retryInterval, CancellationToken cancellationToken)
 {
 var tcs = new TaskCompletionSource<object>();
 
 cancellationToken.Register(() => tcs.TrySetCanceled());
 var timer = new Timer((state) =>
 {
 var taskCompletionSource = (TaskCompletionSource<object>) state;
 try
 { 
 if (retryFunc())
 {
 taskCompletionSource.TrySetResult(null);
 }
 }
 catch (Exception ex)
 {
 taskCompletionSource.TrySetException(ex);
 }
 }, tcs, TimeSpan.FromMilliseconds(0), retryInterval);
 // Once the task is complete, dispose of the timer so it doesn't keep firing. Also captures the timer
 // in a closure so it does not get disposed.
 tcs.Task.ContinueWith(t => timer.Dispose(),
 CancellationToken.None,
 TaskContinuationOptions.ExecuteSynchronously,
 TaskScheduler.Default);
 return tcs.Task;
 }

Update

I updated the code as per @svick's comments. Here is the new version. Working to add overloads for processing of asynchronous retry functions.

 public static Task RetryAsync(Func<bool> retryFunc, TimeSpan retryInterval)
 {
 return RetryAsync(retryFunc, retryInterval, CancellationToken.None);
 }
 public static Task RetryAsync(Func<bool> retryFunc, TimeSpan retryInterval, CancellationToken cancellationToken)
 {
 var tcs = new TaskCompletionSource<object>();
 
 cancellationToken.Register(() => tcs.TrySetCanceled());
 var timer = new Timer((state) =>
 {
 var taskCompletionSource = (TaskCompletionSource<object>) state;
 try
 { 
 if (retryFunc())
 {
 taskCompletionSource.TrySetResult(null);
 }
 }
 catch (Exception ex)
 {
 taskCompletionSource.TrySetException(ex);
 }
 }, tcs, TimeSpan.FromMilliseconds(0), retryInterval);
 // Once the task is complete, dispose of the timer so it doesn't keep firing. Also captures the timer
 // in a closure so it does not get disposed.
 tcs.Task.ContinueWith(t => timer.Dispose(),
 CancellationToken.None,
 TaskContinuationOptions.ExecuteSynchronously,
 TaskScheduler.Default);
 return tcs.Task;
 }
rags-to-riches does not qualify for the community-challenge tag
Link
Simon Forsberg
  • 59.7k
  • 9
  • 157
  • 311
Updated code as per code review from @svick
Source Link
Loading
Added [community-challenge]
Link
RubberDuck
  • 31.1k
  • 6
  • 73
  • 176
Loading
Tweeted twitter.com/#!/StackCodeReview/status/484747180713189376
deleted 8 characters in body; edited title
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238
Loading
added rags to riches
Link
Vogel612
  • 25.5k
  • 7
  • 59
  • 141
Loading
Source Link
Loading
lang-cs

AltStyle によって変換されたページ (->オリジナル) /