InventoryMaterializationRetry.cs 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839
  1. using MySqlConnector;
  2. namespace Admin.NET.Plugin.AiDOP.MaterialWarehouse;
  3. /// <summary>
  4. /// 库存标准层物化 SQL 的死锁重试。只重试 MySQL 1213 / 1205,最多 3 次。
  5. /// </summary>
  6. public static class InventoryMaterializationRetry
  7. {
  8. public const int MaxAttempts = 3;
  9. public static readonly int[] RetryDelayMilliseconds = [250, 750];
  10. public static bool IsRetryable(Exception ex)
  11. {
  12. for (var current = ex; current != null; current = current.InnerException)
  13. {
  14. if (current is MySqlException mysql && (mysql.Number == 1213 || mysql.Number == 1205))
  15. return true;
  16. }
  17. return false;
  18. }
  19. public static async Task<T> ExecuteAsync<T>(Func<Task<T>> action, CancellationToken cancellationToken = default)
  20. {
  21. if (action == null) throw new ArgumentNullException(nameof(action));
  22. for (var attempt = 1; ; attempt++)
  23. {
  24. cancellationToken.ThrowIfCancellationRequested();
  25. try
  26. {
  27. return await action();
  28. }
  29. catch (Exception ex) when (IsRetryable(ex) && attempt < MaxAttempts)
  30. {
  31. await Task.Delay(RetryDelayMilliseconds[attempt - 1], cancellationToken);
  32. }
  33. }
  34. }
  35. }