單個類,簡單好用express
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; } } }
調用示例:spa
//調用門店開通方法,依據結果判斷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好。blog