Occasionally I have a need to retry an operation several times before giving up. My code is like:
int retries = 3;
while(true) {
try {
DoSomething();
I've written a small class based on answers posted here. Hopefully it will help someone: https://github.com/natenho/resiliency
using System;
using System.Threading;
///
/// Classe utilitária para suporte a resiliência
///
public sealed class Resiliency
{
///
/// Define o valor padrão de número de tentativas
///
public static int DefaultRetryCount { get; set; }
///
/// Define o valor padrão (em segundos) de tempo de espera entre tentativas
///
public static int DefaultRetryTimeout { get; set; }
///
/// Inicia a parte estática da resiliência, com os valores padrões
///
static Resiliency()
{
DefaultRetryCount = 3;
DefaultRetryTimeout = 0;
}
///
/// Executa uma e tenta novamente DefaultRetryCount vezes quando for disparada qualquer
///
/// Ação a ser realizada
/// Executa uma vez e realiza outras DefaultRetryCount tentativas em caso de exceção. Não aguarda para realizar novas tentativa.
public static void Try(Action action)
{
Try(action, DefaultRetryCount, TimeSpan.FromMilliseconds(DefaultRetryTimeout), null);
}
///
/// Executa uma e tenta novamente determinado número de vezes quando for disparada qualquer
///
/// Ação a ser realizada
/// Número de novas tentativas a serem realizadas
/// Tempo de espera antes de cada nova tentativa
public static void Try(Action action, int retryCount, TimeSpan retryTimeout)
{
Try(action, retryCount, retryTimeout, null);
}
///
/// Executa uma e tenta novamente determinado número de vezes quando for disparada qualquer
///
/// Ação a ser realizada
/// Número de novas tentativas a serem realizadas
/// Tempo de espera antes de cada nova tentativa
/// Permitindo manipular os critérios para realizar as tentativas
public static void Try(Action action, int retryCount, TimeSpan retryTimeout, Action> tryHandler)
{
Try(action, retryCount, retryTimeout, tryHandler);
}
///
/// Executa uma e tenta novamente por até DefaultRetryCount vezes quando for disparada qualquer
///
/// Ação a ser realizada
/// Permitindo manipular os critérios para realizar as tentativas
/// Executa uma vez e realiza outras DefaultRetryCount tentativas em caso de exceção. Aguarda DefaultRetryTimeout segundos antes de realizar nova tentativa.
public static void Try(Action action, Action> tryHandler)
{
Try(action, DefaultRetryCount, TimeSpan.FromSeconds(DefaultRetryTimeout), null);
}
///
/// Executa uma e tenta novamente determinado número de vezes quando for disparada qualquer
///
/// Ação a ser realizada
/// Executa uma vez e realiza outras DefaultRetryCount tentativas em caso de exceção. Aguarda DefaultRetryTimeout segundos antes de realizar nova tentativa.
public static void Try(Action action) where TException : Exception
{
Try(action, DefaultRetryCount, TimeSpan.FromSeconds(DefaultRetryTimeout), null);
}
///
/// Executa uma e tenta novamente determinado número de vezes quando for disparada qualquer
///
/// Ação a ser realizada
///
public static void Try(Action action, int retryCount) where TException : Exception
{
Try(action, retryCount, TimeSpan.FromSeconds(DefaultRetryTimeout), null);
}
///
/// Executa uma e tenta novamente determinado número de vezes quando for disparada qualquer
///
/// Ação a ser realizada
///
///
public static void Try(Action action, int retryCount, TimeSpan retryTimeout) where TException : Exception
{
Try(action, retryCount, retryTimeout, null);
}
///
/// Executa uma e tenta novamente determinado número de vezes quando for disparada qualquer
///
/// Ação a ser realizada
/// Permitindo manipular os critérios para realizar as tentativas
/// Executa uma vez e realiza outras DefaultRetryCount tentativas em caso de exceção. Aguarda DefaultRetryTimeout segundos antes de realizar nova tentativa.
public static void Try(Action action, Action> tryHandler) where TException : Exception
{
Try(action, DefaultRetryCount, TimeSpan.FromSeconds(DefaultRetryTimeout), tryHandler);
}
///
/// Executa uma e tenta novamente determinado número de vezes quando for disparada uma definida no tipo genérico
///
/// Ação a ser realizada
/// Número de novas tentativas a serem realizadas
/// Tempo de espera antes de cada nova tentativa
/// Permitindo manipular os critérios para realizar as tentativas
/// Construído a partir de várias ideias no post
public static void Try(Action action, int retryCount, TimeSpan retryTimeout, Action> tryHandler) where TException : Exception
{
if (action == null)
throw new ArgumentNullException(nameof(action));
while (retryCount-- > 0)
{
try
{
action();
return;
}
catch (TException ex)
{
//Executa o manipulador de exception
if (tryHandler != null)
{
var callback = new ResiliencyTryHandler(ex, retryCount);
tryHandler(callback);
//A propriedade que aborta pode ser alterada pelo cliente
if (callback.AbortRetry)
throw;
}
//Aguarda o tempo especificado antes de tentar novamente
Thread.Sleep(retryTimeout);
}
}
//Na última tentativa, qualquer exception será lançada de volta ao chamador
action();
}
}
///
/// Permite manipular o evento de cada tentativa da classe de
///
public class ResiliencyTryHandler where TException : Exception
{
#region Properties
///
/// Opção para abortar o ciclo de tentativas
///
public bool AbortRetry { get; set; }
///
/// a ser tratada
///
public TException Exception { get; private set; }
///
/// Identifca o número da tentativa atual
///
public int CurrentTry { get; private set; }
#endregion
#region Constructors
///
/// Instancia um manipulador de tentativa. É utilizado internamente
/// por para permitir que o cliente altere o
/// comportamento do ciclo de tentativas
///
public ResiliencyTryHandler(TException exception, int currentTry)
{
Exception = exception;
CurrentTry = currentTry;
}
#endregion
}