首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# Retry 重試機制實作:基於 BackgroundWorker 的非同步重試框架

     編輯:關於C#

前言:為何需要重試框架

網路呼叫、資料庫操作、外部 API 等易發生暫時性失敗。單純 try-catch 重試會阻塞 UI 執行緒,且缺乏統一的重試策略、進度回報與取消機制。本文封裝 RetryProvider,基於 BackgroundWorker 實作非同步重試,支援自訂等待間隔、重試次數、進度事件與取消。

類別圖 操作示例
圖 1:RetryProvider 類別圖與執行畫面

核心類別設計

RetryProvider 暴露兩個進入點:

  • StartAsync(Action target, int waitTimeout, int retryCount):無回傳值委托。
  • StartAsyncFunc(Func<bool> target, int waitTimeout, int retryCount):回傳 bool 表示成功與否。

內部統一由 StartAsyncRetry 建立/重用 BackgroundWorker,設定 WorkerSupportsCancellation 與 WorkerReportsProgress。

背景執行緒核心邏輯

private void Start(object target)
{
    int retryCount = this.RetryCount;
    lock (_asyncLock)
    {
        _backgroupThread.ReportProgress(5);
        while (!_backgroupThread.CancellationPending)
        {
            PerRetryBegin?.Invoke(RetryCount - retryCount);
            try
            {
                if (target is Action action) { action.Invoke(); InvokeCompletedEvent(true); return; }
                else if (target is Func<bool> func)
                {
                    if (func.Invoke()) { InvokeCompletedEvent(true); return; }
                    throw new InvalidOperationException("Execute Failed.");
                }
            }
            catch (Exception ex)
            {
                PerRetryFailedCompleted?.Invoke(ex);
                _backgroupThread.ReportProgress((RetryCount - retryCount + 1) * 100 / RetryCount);
            }
            finally { PerRetryEnd?.Invoke(RetryCount - retryCount); }

            if (RetryCount > 0)
            {
                retryCount--;
                if (retryCount == 0) { InvokeCompletedEvent(); return; }
            }
            Thread.Sleep(WaitTimeout);
        }
        if (_backgroupThread.CancellationPending) Cancelled?.Invoke();
    }
}

事件模型:完整生命週期通知

  • PerRetryBegin(int retryIndex):單次重試開始 (索引從 0 起)。
  • PerRetryEnd(int retryIndex):單次重試結束。
  • PerRetryFailedCompleted(Exception ex):單次失敗異常資訊。
  • ProgressChanged(int percent):整體進度百分比。
  • Completed(bool success):最終完成狀態。
  • Cancelled():使用者取消。

用戶端呼叫範例

private RetryProvider _retryProvider;

private void btnStart_Click(object sender, EventArgs e)
{
    int waitTimeout = (int)nupWaitTimeout.Value * 1000;
    int retryCount = (int)nupRetryCount.Value;
    if (_retryProvider == null)
    {
        _retryProvider = new RetryProvider();
        _retryProvider.PerRetryFailedCompleted += (ex) => Log($"重試失敗: {ex.Message}");
        _retryProvider.Cancelled += () => Log("已取消");
        _retryProvider.PerRetryBegin += (i) => Log($"第 {i+1} 次重試開始");
        _retryProvider.PerRetryEnd += (i) => Log($"第 {i+1} 次重試結束");
        _retryProvider.ProgressChanged += (p) => progressBar.Value = p;
        _retryProvider.Completed += (ok) => { btnStart.Enabled = true; Log(ok ? "成功" : "最終失敗"); };
    }
    if (_retryProvider.IsBusy) return;
    btnStart.Enabled = false;
    _retryProvider.StartAsyncFunc(ThrowExceptionMethod, waitTimeout, retryCount);
}

private bool ThrowExceptionMethod()
{
    // 模擬不穩定操作
    if (DateTime.Now.Second % 3 == 0) return true;
    throw new Exception("隨機失敗");
}

private void btnCancel_Click(object sender, EventArgs e) => _retryProvider?.Cancel();

適用場景與限制

  • 適用:可控制執行邏輯的操作 (資料庫重連、API 呼叫、檔案存取)。
  • 不適用:不可控的第三方程序 (如啟動 MATLAB、Photoshop 等外部進程),此類建議用 Timer 輪詢進度條。

原始碼下載:重試解決方案原始碼

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved