一個簡單的異常/條件重試類(C#)

 

單個類,簡單好用

using System;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;

namespace Qing
{
    public static class QRetry
    {
        /// <summary>
        /// 自定義異常重試
        /// </summary>
        /// <typeparam name="E"></typeparam>
        /// <param name="time"></param>
        /// <param name="wait"></param>
        /// <param name="action"></param>
        /// <param name="retryInfo"></param>
        public static void HandException<E>(int time, TimeSpan wait, Action action, Action<E, int, TimeSpan> retryInfo = null) where E : Exception
        {
            var task = Task.Run(() =>
            {
                for (int i = 0; i < (time + 1); i++)
                {
                    try
                    {
                        action();
                        break;
                    }
                    catch (E e)
                    {
                        if (i == time)
                        {
                            break;
                        }
                        retryInfo?.Invoke(e, i + 1, wait);
                        Thread.Sleep(wait);
                    }
                }

            });

        }
        /// <summary>
        /// 自定義異常重試(有返回,異常返回默認值)
        /// </summary>
        /// <typeparam name="TResult">返回結果</typeparam>
        /// <param name="time">次數</param>
        /// <param name="wait">等待時間</param>
        /// <param name="action">動作</param>
        /// <param name="retryInfo">重試信息</param>
        /// <returns></returns>
        public static TResult HandException<E, TResult>(int time, TimeSpan wait, Func<TResult> action, Action<E, int, TimeSpan> retryInfo = null) where E : Exception
        {
            return Task.Run(() =>
            {
                TResult result = default(TResult);
                for (int i = 0; i < (time + 1); i++)
                {
                    try
                    {
                        result = action();
                        break;
                    }
                    catch (E e)
                    {
                        if (i == time)
                        {
                            break;
                        }
                        retryInfo?.Invoke(e, i + 1, wait);
                        Thread.Sleep(wait);
                    }
                }
                return result;
            }).Result;
        }
        /// <summary>
        /// 自定義異常重試(有返回,設置異常返回值)
        /// </summary>
        /// <typeparam name="TResult">返回結果</typeparam>
        /// <param name="time">次數</param>
        /// <param name="wait">每次等待時間</param>
        /// <param name="failedValue">失敗返回值</param>
        /// <param name="func">執行方法</param>
        /// <param name="retryInfo">重試信息(Exception,Time,TimeSpan)</param>
        /// <returns></returns>
        public static TResult HandException<E, TResult>(int time, TimeSpan wait, TResult failedValue, Func<TResult> func, Action<E, int, TimeSpan> retryInfo = null) where E : Exception
        {
            return Task.Run(() =>
            {
                TResult result = failedValue;
                for (int i = 0; i < (time + 1); i++)
                {
                    try
                    {
                        result = func();
                        break;
                    }
                    catch (E e)
                    {
                        if (i == time)
                        {
                            break;
                        }
                        retryInfo?.Invoke(e, i + 1, wait);
                        Thread.Sleep(wait);
                    }
                }
                return result;
            }).Result;
        }
        /// <summary>
        /// 自定義異常重試
        /// </summary>
        /// <param name="waits">重試間隔</param>
        /// <param name="action">運行方法</param>
        /// <param name="retryInfo">重試信息</param>
        public static void HandException<E>(TimeSpan[] waits, Action action, Action<E, int, TimeSpan> retryInfo = null) where E : Exception
        {
            var task = Task.Run(() =>
            {
                for (int i = 0; i < (waits.Length + 1); i++)
                {
                    try
                    {
                        action();
                        break;
                    }
                    catch (E e)
                    {
                        if (i == waits.Length)
                        {
                            break;
                        }
                        retryInfo?.Invoke(e, i + 1, waits[i]);
                        Thread.Sleep(waits[i]);
                    }
                }

            });
        }
        /// <summary>
        /// 自定義異常重試 (有返回,異常返回默認值)
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="waits"></param>
        /// <param name="func"></param>
        /// <param name="retryInfo"></param>
        /// <returns></returns>
        public static TResult HandException<E, TResult>(TimeSpan[] waits, Func<TResult> func, Action<E, int, TimeSpan> retryInfo = null) where E : Exception
        {
            return Task.Run(() =>
            {
                TResult result = default(TResult);
                for (int i = 0; i < (waits.Length + 1); i++)
                {
                    try
                    {
                        result = func();
                        break;
                    }
                    catch (E e)
                    {
                        if (i == waits.Length)
                        {
                            break;
                        }
                        retryInfo?.Invoke(e, i + 1, waits[i]);
                        Thread.Sleep(waits[i]);
                    }
                }
                return result;
            }).Result;
        }

        /// <summary>
        /// 自定義異常重試 (有返回,設置異常返回值)
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="waits"></param>
        /// <param name="func"></param>
        /// <param name="retryInfo"></param>
        /// <returns></returns>
        public static TResult HandException<E, TResult>(TimeSpan[] waits, TResult failedValue, Func<TResult> func, Action<E, int, TimeSpan> retryInfo = null) where E : Exception
        {
            return Task.Run(() =>
            {
                TResult result = failedValue;
                for (int i = 0; i < (waits.Length + 1); i++)
                {
                    try
                    {
                        result = func();
                        break;
                    }
                    catch (E e)
                    {
                        if (i == waits.Length)
                        {
                            break;
                        }
                        retryInfo?.Invoke(e, i + 1, waits[i]);
                        Thread.Sleep(waits[i]);
                    }
                }
                return result;
            }).Result;
        }

        /// <summary>
        /// 結果判斷重試(異常也重試)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <param name="time"></param>
        /// <param name="wait"></param>
        /// <param name="func"></param>
        /// <param name="retryInfo"></param>
        /// <returns></returns>
        public static T HandResult<T>(Expression<Func<T, bool>> expression, int time, TimeSpan wait, Func<T> func, Action<string, int, TimeSpan> retryInfo = null)
        {
            var exp = expression.Compile();
            return Task.Run(() =>
            {
                var result = default(T);
                for (int i = 0; i < (time + 1); i++)
                {
                    try
                    {
                        result = func();
                        if (i == time)
                        {
                            break;
                        }
                        else if (exp.Invoke(result))
                        {
                            retryInfo?.Invoke("結果命中約束條件", i + 1, wait);
                            Thread.Sleep(wait);
                            continue;
                        }
                        else
                        {
                            break;
                        }
                    }
                    catch (Exception e)
                    {
                        if (i == time)
                        {
                            break;
                        }
                        retryInfo?.Invoke(e.Message, i + 1, wait);
                        Thread.Sleep(wait);
                    }
                }
                return result;
            }).Result;
           
        }

        /// <summary>
        /// 結果判斷重試(異常也重試)
        /// </summary>
        /// <typeparam name="T">返回類型</typeparam>
        /// <param name="expression">判斷表達式</param>
        /// <param name="waits">每次重試間隔</param>
        /// <param name="func">執行方法</param>
        /// <param name="retryInfo">重試信息</param>
        /// <returns></returns>
        public static T HandResult<T>(Expression<Func<T, bool>> expression, TimeSpan[] waits, Func<T> func, Action<string, int, TimeSpan> retryInfo = null)
        {
            var exp = expression.Compile();
            return Task.Run(() =>
            {
                var result = default(T);
                for (int i = 0; i < (waits.Length + 1); i++)
                {
                    try
                    {
                        result = func();
                        if (i == waits.Length)
                        {
                           
                            break;
                        }
                        else if (exp.Invoke(result))
                        {
                            retryInfo?.Invoke("結果命中約束條件", i + 1, waits[i]);
                            Thread.Sleep(waits[i]);
                            continue;
                        }
                        else
                        {
                            break;
                        }
                    }
                    catch (Exception e)
                    {
                        if (i == waits.Length)
                        {
                            break;
                        }
                        retryInfo?.Invoke(e.Message, i + 1, waits[i]);
                        Thread.Sleep(waits[i]);
                    }
                }
                return result;
            }).Result;
        }
    }

}

  

調用示例:

//調用門店開通方法,依據結果判斷Result!="OK",那麼過 20秒再重試,一共重試20次
var createResult = Qing.QRetry.HandResult<CreateStoreResult>(x => x.result != "OK", 20, TimeSpan.FromSeconds(20), () =>
   {
      //開店動作
      return StoreManager.Instance.CreateStore(storeArg);

   }, (msg, count, ts) =>
      {
          Qing.QLog.SendLog_Debug($"{storeName}開通執行異常:{msg};{ts.TotalSeconds}s 後進行第{count}次重試。");
      }
);

 

方法命名上參考了Polly。正經項目還是用Polly好。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章