Skip to content

Instantly share code, notes, and snippets.

@renestein
Forked from rarous/gist:4352819
Last active October 19, 2022 06:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save renestein/4353381 to your computer and use it in GitHub Desktop.
Save renestein/4353381 to your computer and use it in GitHub Desktop.
Aleš Roubíček Task with retry logic.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TaskWithRetry
{
internal class Program
{
private static void Main(string[] args)
{
var task1 = Task<bool>.Factory.StartWithRetry(() =>
{
Console.WriteLine("running first task");
throw new InvalidOperationException();
return true;
}, 3);
bool isFirstCall = true;
var task2 = Task<bool>.Factory.StartWithRetry(() =>
{
Console.WriteLine("running second task");
if (isFirstCall)
{
isFirstCall = false;
throw new InvalidOperationException();
}
return true;
}, 3);
try
{
Console.WriteLine(task1.Result);
Console.WriteLine(task2.Result);
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.ReadLine();
}
}
}
using System;
using System.Threading.Tasks;
namespace TaskWithRetry
{
public static class TaskFactoryExtensions
{
public const int MIN_ATTEMPTS = 1;
public static Task<TResult> StartWithRetry<TResult>(this TaskFactory<TResult> taskFactory, Func<TResult> func,
int maxAttemps)
{
if (taskFactory == null)
{
throw new ArgumentNullException("taskFactory");
}
if (func == null)
{
throw new ArgumentNullException("func");
}
if (maxAttemps < MIN_ATTEMPTS)
{
throw new ArgumentException("maxAttemps");
}
var tcs = new TaskCompletionSource<TResult>();
int maxAttemptsOriginal = maxAttemps;
Action<Task> wrapperfunction = null;
wrapperfunction = previousTask =>
{
if (maxAttemptsOriginal == 0)
{
//previousTask cannot be null!
tcs.TrySetException(previousTask.Exception);
return;
}
maxAttemptsOriginal--;
var task = taskFactory.StartNew(func);
task.ContinueWith(wrapperfunction, TaskContinuationOptions.OnlyOnFaulted);
task.ContinueWith(prevTask =>
{
if (prevTask.Status == TaskStatus.Canceled)
{
tcs.TrySetCanceled();
}
else
{
tcs.TrySetResult(prevTask.Result);
}
},
TaskContinuationOptions.NotOnFaulted
);
};
wrapperfunction(null);
return tcs.Task;
}
}
}
@renestein
Copy link
Author

Ještě by bylo lepší lépe ošetřovat všechny výjimky, ošetřit lépe všechny stavy tasku., pracovat se SynchronizationContextem, zredukovat počet spouštěných tasků apod.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment