123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- using System;
- using System.Collections.Generic;
- using System.Threading;
- using VCommon.Logging;
- namespace VCommon.Diagnostics
- {
- public abstract class Retry
- {
- public static void Do(Action action, int maxTry = 3, int retryIntervalMs = 500
- , Action<int> onAttempting = null
- , Action<int> onSuccess = null
- , Func<int, Exception, bool> onFail = null
- , Action<IReadOnlyList<Exception>> onAbort = null)
- {
- Do<object>(() =>
- {
- action();
- return null;
- }, maxTry, retryIntervalMs, onAttempting, onSuccess, onFail, onAbort);
- }
- public static T Do<T>(Func<T> func, int maxTry = 3, int retryIntervalMs = 500
- , Action<int> onAttempting = null
- , Action<int> onSuccess = null
- , Func<int, Exception, bool> onFail = null
- , Action<IReadOnlyList<Exception>> onAbort = null)
- {
- var exceptions = new List<Exception>(maxTry);
- var attempt = 0;
- while (++attempt < maxTry)
- {
- try
- {
- onAttempting?.Invoke(attempt);
- var r = func();
- onSuccess?.Invoke(attempt);
- return r;
- }
- catch (Exception e)
- {
- exceptions.Add(e);
- if (false == (onFail?.Invoke(attempt, e) ?? true)) return default(T);
- Thread.Sleep(retryIntervalMs);
- }
- }
- var arr = exceptions.ToArray();
- onAbort?.Invoke(arr);
- throw new AggregateException(arr);
- }
- }
- public class RetryPolicy
- {
- public int MaxTry { get; }
- public int RetryIntervalMs { get; }
- public string Tag { get; }
- public bool ThrowOnAbort { get; set; }
- public RetryPolicy(string tag = null, int maxTry = 3, int retryIntervalMs = 500)
- {
- if (maxTry < 1) throw new ArgumentOutOfRangeException(nameof(maxTry));
- if (retryIntervalMs < 0) throw new ArgumentOutOfRangeException(nameof(maxTry));
- MaxTry = maxTry;
- RetryIntervalMs = retryIntervalMs;
- Tag = tag;
- }
- public void Do(Action action) => Retry.Do(action, MaxTry, RetryIntervalMs, OnAttempting, OnSuccess, OnFail, OnAbort);
- public T Do<T>(Func<T> func) => Retry.Do(func, MaxTry, RetryIntervalMs, OnAttempting, OnSuccess, OnFail, OnAbort);
- protected virtual void OnAttempting(int attempted)
- {
- //Logger.Debug($"Attempting {Tag}", new { attempted });
- }
- protected virtual void OnSuccess(int attempted)
- {
- //Logger.Debug($"Success {Tag}", new { attempted });
- }
- protected virtual bool OnFail(int attempted, Exception exception)
- {
- Logger.Warn($"Fail {Tag}", new { attempted });
- return true;
- }
- protected virtual void OnAbort(IReadOnlyList<Exception> exceptions)
- {
- Logger.Error($"Abort {Tag}", new { exceptions });
- if (ThrowOnAbort) throw new AggregateException(exceptions);
- }
- }
- }
|