Cleanest way to write retry logic?

前端 未结 29 2564
旧巷少年郎
旧巷少年郎 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:44

    I had the need to pass some parameter to my method to retry, and have a result value; so i need an expression.. I build up this class that does the work (it is inspired to the the LBushkin's one) you can use it like this:

    static void Main(string[] args)
    {
        // one shot
        var res = Retry.Do(() => retryThis("try"), 4, TimeSpan.FromSeconds(2), fix);
    
        // delayed execute
        var retry = new Retry(() => retryThis("try"), 4, TimeSpan.FromSeconds(2), fix);
        var res2 = retry.Execute();
    }
    
    static void fix()
    {
        Console.WriteLine("oh, no! Fix and retry!!!");
    }
    
    static string retryThis(string tryThis)
    {
        Console.WriteLine("Let's try!!!");
        throw new Exception(tryThis);
    }
    
    public class Retry
    {
        Expression> _Method;
        int _NumRetries;
        TimeSpan _RetryTimeout;
        Action _OnFailureAction;
    
        public Retry(Expression> method, int numRetries, TimeSpan retryTimeout, Action onFailureAction)
        {
            _Method = method;
            _NumRetries = numRetries;
            _OnFailureAction = onFailureAction;
            _RetryTimeout = retryTimeout;
        }
    
        public TResult Execute()
        {
            TResult result = default(TResult);
            while (_NumRetries > 0)
            {
                try
                {
                    result = _Method.Compile()();
                    break;
                }
                catch
                {
                    _OnFailureAction();
                    _NumRetries--;
                    if (_NumRetries <= 0) throw; // improved to avoid silent failure
                    Thread.Sleep(_RetryTimeout);
                }
            }
            return result;
        }
    
        public static TResult Do(Expression> method, int numRetries, TimeSpan retryTimeout, Action onFailureAction)
        {
            var retry = new Retry(method, numRetries, retryTimeout, onFailureAction);
            return retry.Execute();
        }
    }
    

    ps. the LBushkin's solution does one more retry =D

提交回复
热议问题