Cleanest way to write retry logic?

前端 未结 29 2587
旧巷少年郎
旧巷少年郎 2020-11-22 03:01

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();
         


        
29条回答
  •  攒了一身酷
    2020-11-22 03:42

    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
    
    }
    

提交回复
热议问题