Files
test_demo/MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/Common/RetryMechanism.cs
Shi.Ji e31d3560bb 添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
2026-05-18 11:43:09 +08:00

233 lines
9.3 KiB
C#

using System;
using System.Threading;
using System.Threading.Tasks;
namespace MainShell.Common
{
public class RetryMechanism
{
// 自定义异常:操作失败
public class RetryException : Exception
{
public RetryException(string message) : base(message) { }
}
public class RetryResult
{
public bool Succeeded { get; set; }
public bool IsAborted { get; set; }
public int AttemptCount { get; set; }
public int MaxAttempts { get; set; }
public string Message { get; set; }
}
/// <summary>
/// 向后兼容旧接口:默认直接继续重试直到达到最大次数,失败时抛异常。
/// 新代码建议优先使用 <see cref="RetryOrThrow(Func{bool}, Func{int, bool}, string, int)"/> 或返回结果对象的重载。
/// </summary>
public static void RetryIfNeeded(Func<bool> checkCondition, string message, int maxAttempts = 3)
{
RetryOrThrow(checkCondition, attempt => true, message, maxAttempts);
}
/// <summary>
/// 执行同步重试并返回结果对象。
/// </summary>
/// <param name="checkCondition">
/// 每次尝试时执行的检查逻辑。
/// 返回 <c>true</c> 表示成功,返回 <c>false</c> 表示本次失败并根据 <paramref name="shouldRetry"/> 决定是否继续。
/// 如果该委托抛出异常,则异常会直接向外传播,不会被当前重试机制捕获或吞掉,也不会自动进入下一次重试。
/// </param>
/// <param name="shouldRetry">当一次尝试失败后,决定是否继续重试。参数为当前已完成的尝试次数,从 1 开始计数。</param>
/// <param name="message">操作描述信息。</param>
/// <param name="maxAttempts">最大尝试次数,必须大于 0。</param>
public static RetryResult RetryIfNeeded(Func<bool> checkCondition, Func<int, bool> shouldRetry, string message, int maxAttempts = 3)
{
if (checkCondition == null)
{
throw new ArgumentNullException(nameof(checkCondition));
}
if (shouldRetry == null)
{
throw new ArgumentNullException(nameof(shouldRetry));
}
if (maxAttempts <= 0)
{
throw new ArgumentOutOfRangeException(nameof(maxAttempts), "maxAttempts must be greater than 0.");
}
for (int attempt = 1; attempt <= maxAttempts; attempt++)
{
bool conditionMet = checkCondition();
if (conditionMet)
{
return new RetryResult
{
Succeeded = true,
AttemptCount = attempt,
MaxAttempts = maxAttempts,
Message = message
};
}
if (attempt == maxAttempts)
{
return new RetryResult
{
Succeeded = false,
AttemptCount = attempt,
MaxAttempts = maxAttempts,
Message = message
};
}
bool continueRetry = shouldRetry(attempt);
if (!continueRetry)
{
return new RetryResult
{
Succeeded = false,
IsAborted = true,
AttemptCount = attempt,
MaxAttempts = maxAttempts,
Message = message
};
}
}
return new RetryResult
{
Succeeded = false,
AttemptCount = maxAttempts,
MaxAttempts = maxAttempts,
Message = message
};
}
// 保留抛异常风格的兼容方法
public static void RetryOrThrow(Func<bool> checkCondition, Func<int, bool> shouldRetry, string message, int maxAttempts = 3)
{
var result = RetryIfNeeded(checkCondition, shouldRetry, message, maxAttempts);
EnsureSuccess(result);
}
/// <summary>
/// 向后兼容旧接口的异步版本:默认直接继续重试直到达到最大次数,失败时抛异常。
/// 新代码建议优先使用 <see cref="RetryOrThrowAsync(Func{Task{bool}}, Func{int, Task{bool}}, string, int, CancellationToken)"/> 或返回结果对象的重载。
/// </summary>
public static async Task RetryIfNeededAsync(Func<Task<bool>> checkConditionAsync, string message, int maxAttempts = 3)
{
await RetryOrThrowAsync(checkConditionAsync, attempt => Task.FromResult(true), message, maxAttempts, CancellationToken.None).ConfigureAwait(false);
}
/// <summary>
/// 执行异步重试并返回结果对象。
/// </summary>
/// <param name="checkConditionAsync">
/// 每次尝试时执行的异步检查逻辑。
/// 返回 <c>true</c> 表示成功,返回 <c>false</c> 表示本次失败并根据 <paramref name="shouldRetryAsync"/> 决定是否继续。
/// 如果该委托抛出异常,则异常会直接向外传播,不会被当前重试机制捕获或吞掉,也不会自动进入下一次重试。
/// </param>
/// <param name="shouldRetryAsync">当一次尝试失败后,决定是否继续重试。参数为当前已完成的尝试次数,从 1 开始计数。</param>
/// <param name="message">操作描述信息。</param>
/// <param name="maxAttempts">最大尝试次数,必须大于 0。</param>
/// <param name="cancellationToken">用于取消异步重试流程。</param>
public static async Task<RetryResult> RetryIfNeededAsync(Func<Task<bool>> checkConditionAsync, Func<int, Task<bool>> shouldRetryAsync, string message, int maxAttempts = 3, CancellationToken cancellationToken = default(CancellationToken))
{
if (checkConditionAsync == null)
{
throw new ArgumentNullException(nameof(checkConditionAsync));
}
if (shouldRetryAsync == null)
{
throw new ArgumentNullException(nameof(shouldRetryAsync));
}
if (maxAttempts <= 0)
{
throw new ArgumentOutOfRangeException(nameof(maxAttempts), "maxAttempts must be greater than 0.");
}
for (int attempt = 1; attempt <= maxAttempts; attempt++)
{
cancellationToken.ThrowIfCancellationRequested();
bool conditionMet = await checkConditionAsync().ConfigureAwait(false);
if (conditionMet)
{
return new RetryResult
{
Succeeded = true,
AttemptCount = attempt,
MaxAttempts = maxAttempts,
Message = message
};
}
if (attempt == maxAttempts)
{
return new RetryResult
{
Succeeded = false,
AttemptCount = attempt,
MaxAttempts = maxAttempts,
Message = message
};
}
cancellationToken.ThrowIfCancellationRequested();
bool continueRetry = await shouldRetryAsync(attempt).ConfigureAwait(false);
if (!continueRetry)
{
return new RetryResult
{
Succeeded = false,
IsAborted = true,
AttemptCount = attempt,
MaxAttempts = maxAttempts,
Message = message
};
}
}
return new RetryResult
{
Succeeded = false,
AttemptCount = maxAttempts,
MaxAttempts = maxAttempts,
Message = message
};
}
// 保留抛异常风格的异步兼容方法
public static async Task RetryOrThrowAsync(Func<Task<bool>> checkConditionAsync, Func<int, Task<bool>> shouldRetryAsync, string message, int maxAttempts = 3, CancellationToken cancellationToken = default(CancellationToken))
{
var result = await RetryIfNeededAsync(checkConditionAsync, shouldRetryAsync, message, maxAttempts, cancellationToken).ConfigureAwait(false);
EnsureSuccess(result);
}
private static void EnsureSuccess(RetryResult result)
{
if (result.Succeeded)
{
return;
}
if (result.IsAborted)
{
throw new RetryException($"{result.Message} 已中止重试,操作失败。尝试次数: {result.AttemptCount}/{result.MaxAttempts}");
}
throw new RetryException($"{result.Message} 已达到最大重试次数,操作失败。尝试次数: {result.AttemptCount}/{result.MaxAttempts}");
}
}
}