提供一個可排程、非同步的工作處理,此套件同時提供免費版本和付費版本,免費版本可商業使用,付費版本則是額外提供進階的功能,詳細可到 Hangfire 官網 查看
本篇不會介紹如何使用 Hangfire,而是會聚焦在於如何實作自訂工作重試處理。Hangfire 本身雖然已經提供工作重試處理,但是如果對於工作重試處理有特定的需求,就可以自己實作工作重試處理
如果符合以需求皆適用:
客製工作重試處理的實作會透過一個 Hangfire Job Filter 來處理,實作範例是一個讓服務忙碌重試和錯誤重試擁有各自獨立的重試計數器和重試間隔時間
建立先建立一個 自訂 Job Filter 參數,用來傳遞工作重試計數器和重試間隔時間
public class CustomAutoRetryOptions
{
// 發生錯誤時,最大重試次數
public int ErrorRetryAttempts { get; set; }
// 錯誤的重試間隔秒數
public int ErrorRetryDelayInSeconds { get; set;}
// 服務忙碌時,最大重試次數
public int BusyRetryAttempts { get; set; }
// 服務忙碌的重試間隔秒數
Public int BusyRetryDelayInSeconds { get; set; }
public CustomAutoRetryOptions()
{
}
public CustomAutoRetryOptions(CustomAutoRetryOptions options)
{
ErrorRetryAttempts = options.ErrorRetryAttempts;
ErrorRetryDelayInSeconds = options.ErrorRetryDelayInSeconds;
BusyRetryAttempts = options.BusyRetryAttempts;
BusyRetryDelayInSeconds = options.BusyRetryDelayInSeconds;
}
}
建立一個 Job Filter Attribute,繼承 JobFilterAttribute 和 IElectStateFilter
加入 Custom Job 參數
ErrorRetryAttempts ─ 錯誤重試ErrorRetryDelayInSeconds ─ 錯誤重試間隔BusyRetryAttempts ─ 服務忙碌重試BusyRetryDelayInSeconds ─ 服務忙碌重試間隔加入其他屬性
實作建構函式
實作 Custom Job Filter 的 OnStateElection,詳細內容會在 Step.3 說明
// [1] 建立一個 Job Filter Attribute,繼承 JobFilterAttribute 和 IElectStateFilter
public class CustomAutoRetryAttribute : JobFilterAttribute, IElectStateFilter
{
// [2] 加入 Custom Job 參數
public int ErrorRetryAttempts { get; set; } = 3;
public int ErrorRetryDelayInSeconds { get; set; } = 5;
public int BusyRetryAttempts { get; set; } = 3;
public int BusyRetryDelayInSeconds { get; set; } = 5;
// [3] 加入其他屬性
public bool LogEvents { get; set; }
public AttemptsExceededAction OnAttemptsExceeded { get; set; }
// [4] 建構函式
public CustomAutoRetryAttribute()
{
LogEvents = true;
OnAttemptsExceeded = AttemptsExceededAction.Fail;
Order = 20;
}
// [5] 實作 Custom Job Filter 的 OnStateElection
public void OnStateElection(ElectStateContext context)
{
// 詳細內容會在 Step.3 說明
}
}
覆寫 OnStateElection
可以依據 Exception 類型做對應的處理
取出 Custom Job Filter Options
取出的來源有兩個:
CustomAutoRetryAttribute 設定的值 (固定值)
// [1] 覆寫 OnStateElection
public void OnStateElection(ElectStateContext context)
{
// Job 執行結束,檢查 Job 執行狀態
if (context.CandidateState is FailedState &&
context.CandidateState != null)
{ // Job 執行失敗 (發生 Exception) 時的處理
var failedState = context.CandidateState as FailedState;
// [3] 取出 Custom Job Filter Options
var options = GetAutoRetryOptions(context);
// [2] 依據 Exception 類型做對應的處理
if (failedState.Exception != null && failedState.Exception is BusyServiceException)
{ // 服務忙碌時
// TODO: do something
}
else
{ // 其他錯誤時
// TODO: do something
}
}
}
// [3] 試著從 Job Function Arguments 中取出 Custom Job Filter Options
private CustomAutoRetryOptions GetAutoRetryOptions(ElectStateContext context)
{
// (動態) 從 Job Function Arguments 中取出 Custom Job Filter Options
var args = context.BackgroundJob.Job.Args.ToList();
foreach (var arg in args)
{
if (arg.GetType() == typeof(CustomAutoRetryOptions))
{
return new CustomAutoRetryOptions((CustomAutoRetryOptions)arg);
}
}
// (固定) 取出 Custom Job Filter 的設定作為 Custom Job Filter Options
return new CustomAutoRetryOptions() {
ErrorRetryAttempts = ErrorRetryAttempts,
ErrorRetryDelayInSeconds = ErrorRetryDelayInSeconds,
BusyRetryAttempts = BusyRetryAttempts,
BusyRetryDelayInSeconds = BusyRetryDelayInSeconds
};
}
public class BusyServiceException : Exception
{
}
將 Custom Job Filter 加入到 Hangfire Filters
Startup.cs
using Hangfire;
public class Startup
{
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// 將 Custom Job Filter 加入到 Hangfire Filters
GlobalJobFilters.Filters.Add(new CustomAutoRetryAttribute());
}
}
在 Job Method 前面加上 CustomAutoRetry
原生的 Auto Retry 處理必須關閉,不然 CustomAutoRetry 處理完後,緊接的執行原生的 Auto Retry
靜態指派最大重試次數、重試間隔時間
CustomAutoRetryAttribute 加入重試次數、重試間隔時間動態指派最大重試次數、重試間隔時間
可以透過 Throw Exception 來觸發 Job Retry
// 自訂 Retry 處理 (動態指派計數器、間隔時間)
[CustomAutoRetry()]
[AutomaticRetry(Attempts = 0)] // 關閉原生的 Retry 處理
public Task DoErrorThing(CustomAutoRetryOptions retryOptions)
{
// TODO: Do SomeThing
// 透過 Throw Exception 來觸發 Job Retry
throw new BusyServiceException();
}
// 自訂 Retry 處理 (靜態指派計數器、間隔時間)
[CustomAutoRetry(BusyRetryAttempts = 3, BusyRetryDelayInSeconds = 120)]
[AutomaticRetry(Attempts = 0)] // 關閉原生的 Retry 處理
public Task DoBusyThing()
{
// TODO: Do SomeThing
// 透過 Throw Exception 來觸發 Job Retry
throw new BusyServiceException();
}
執行工作
CustomAutoRetryOptions 可以動態指派最大重試次數、重試間隔時間
// 非同步處理 Request
var retryOptions = new CustomAutoRetryOptions();
// 設定錯誤重試、服務忙碌重試的次數和間隔時間
int errorRetryAttempts = 3;
int errorRetryDelayInSeconds = 10;
int busyRetryAttempts = 5;
int busyRetryDelayInSeconds = 60;
retryOptions = retryOptions.SetErrorRetry(errorRetryAttempts, errorRetryDelayInSeconds)
.SetBusyRetry(busyRetryAttempts, busyRetryDelayInSeconds);
// 錯誤重試、服務忙碌重試的次數和間隔時間的設定需要傳入 (動態指派)
BackgroundJob.Enqueue<DemoJob>(job => job.DoErrorThing(retryOptions));
// 錯誤重試、服務忙碌重試的次數和間隔時間的設定需要傳入 (靜態指派)
BackgroundJob.Enqueue<DemoJob>(job => job.DoBusyThing());
When you subscribe to the blog, we will send you an e-mail when there are new updates on the site so you wouldn't miss them.
評論