如何获取 Hangfire 后台作业的当前尝试次数?
How do I get the current attempt number on a background job in Hangfire?
在我的 Hangfire 后台作业最后一次尝试结束之前,我需要执行一些数据库操作(我需要删除与该作业相关的数据库记录)
我当前的工作设置了以下属性:
[AutomaticRetry(Attempts = 5, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
考虑到这一点,我需要确定当前的尝试次数是多少,但我很难从 Google 搜索或 Hangfire.io 文档中找到这方面的任何文档。
您可以使用 IServerFilter
的 OnPerforming
或 OnPerformed
方法,如果您想检查尝试,或者如果您想要,您可以等待 OnStateElection
16=]。我不知道你到底有什么要求,所以这取决于你。这是您想要的代码:)
public class JobStateFilter : JobFilterAttribute, IElectStateFilter, IServerFilter
{
public void OnStateElection(ElectStateContext context)
{
// all failed job after retry attempts comes here
var failedState = context.CandidateState as FailedState;
if (failedState == null) return;
}
public void OnPerforming(PerformingContext filterContext)
{
// do nothing
}
public void OnPerformed(PerformedContext filterContext)
{
// you have an option to move all code here on OnPerforming if you want.
var api = JobStorage.Current.GetMonitoringApi();
var job = api.JobDetails(filterContext.BackgroundJob.Id);
foreach(var history in job.History)
{
// check reason property and you will find a string with
// Retry attempt 3 of 3: The method or operation is not implemented.
}
}
}
如何添加过滤器
GlobalJobFilters.Filters.Add(new JobStateFilter());
----- or
var options = new BackgroundJobServerOptions
{
FilterProvider = new JobFilterCollection { new JobStateFilter() };
};
app.UseHangfireServer(options, storage);
示例输出:
只需将 PerformContext
添加到您的工作方法;您还可以从此对象访问您的 JobId
。对于尝试次数,这仍然依赖于魔术字符串,但它比 current/only 答案更不可靠:
public void SendEmail(PerformContext context, string emailAddress)
{
string jobId = context.BackgroundJob.Id;
int retryCount = context.GetJobParameter<int>("RetryCount");
// send an email
}
(注意!这是 OP 问题的解决方案。它没有回答“如何获取当前尝试次数”的问题。如果这是你想要的,请参见 例如)
使用工作过滤器和 OnStateApplied
回调:
public class CleanupAfterFailureFilter : JobFilterAttribute, IServerFilter, IApplyStateFilter
{
public void OnStateApplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
{
try
{
var failedState = context.NewState as FailedState;
if (failedState != null)
{
// Job has finally failed (retry attempts exceeded)
// *** DO YOUR CLEANUP HERE ***
}
}
catch (Exception)
{
// Unhandled exceptions can cause an endless loop.
// Therefore, catch and ignore them all.
// See notes below.
}
}
public void OnStateUnapplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
{
// Must be implemented, but can be empty.
}
}
将过滤器直接添加到工作函数中:
[CleanupAfterFailureFilter]
public static void MyJob()
或全局添加:
GlobalJobFilters.Filters.Add(new CleanupAfterFailureFilter ());
或者像这样:
var options = new BackgroundJobServerOptions
{
FilterProvider = new JobFilterCollection { new CleanupAfterFailureFilter () };
};
app.UseHangfireServer(options, storage);
或参阅 http://docs.hangfire.io/en/latest/extensibility/using-job-filters.html 了解有关职位筛选器的更多信息。
注意:这是基于已接受的答案:
不同之处在于使用了OnStateApplied
而不是OnStateElection
,所以只有在达到最大重试次数后才会调用过滤器回调。这种方法的缺点是无法中断状态转换为“失败”,但在这种情况下和大多数情况下都不需要这样做,您只想在作业失败后进行一些清理。
注意:空 catch
处理程序是不好的,因为它们可以隐藏错误并使它们难以在生产中调试。这是必要的,所以回调不会永远被重复调用。出于调试目的,您可能希望记录异常。还建议降低作业过滤器中出现异常的风险。一种可能性是,不是就地进行清理工作,而是安排一个新的后台作业,该作业在原始作业失败时运行。不过,请注意不要对其应用过滤器 CleanupAfterFailureFilter
。不要全局注册它,或者给它添加一些额外的逻辑...
在我的 Hangfire 后台作业最后一次尝试结束之前,我需要执行一些数据库操作(我需要删除与该作业相关的数据库记录)
我当前的工作设置了以下属性:
[AutomaticRetry(Attempts = 5, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
考虑到这一点,我需要确定当前的尝试次数是多少,但我很难从 Google 搜索或 Hangfire.io 文档中找到这方面的任何文档。
您可以使用 IServerFilter
的 OnPerforming
或 OnPerformed
方法,如果您想检查尝试,或者如果您想要,您可以等待 OnStateElection
16=]。我不知道你到底有什么要求,所以这取决于你。这是您想要的代码:)
public class JobStateFilter : JobFilterAttribute, IElectStateFilter, IServerFilter
{
public void OnStateElection(ElectStateContext context)
{
// all failed job after retry attempts comes here
var failedState = context.CandidateState as FailedState;
if (failedState == null) return;
}
public void OnPerforming(PerformingContext filterContext)
{
// do nothing
}
public void OnPerformed(PerformedContext filterContext)
{
// you have an option to move all code here on OnPerforming if you want.
var api = JobStorage.Current.GetMonitoringApi();
var job = api.JobDetails(filterContext.BackgroundJob.Id);
foreach(var history in job.History)
{
// check reason property and you will find a string with
// Retry attempt 3 of 3: The method or operation is not implemented.
}
}
}
如何添加过滤器
GlobalJobFilters.Filters.Add(new JobStateFilter());
----- or
var options = new BackgroundJobServerOptions
{
FilterProvider = new JobFilterCollection { new JobStateFilter() };
};
app.UseHangfireServer(options, storage);
示例输出:
只需将 PerformContext
添加到您的工作方法;您还可以从此对象访问您的 JobId
。对于尝试次数,这仍然依赖于魔术字符串,但它比 current/only 答案更不可靠:
public void SendEmail(PerformContext context, string emailAddress)
{
string jobId = context.BackgroundJob.Id;
int retryCount = context.GetJobParameter<int>("RetryCount");
// send an email
}
(注意!这是 OP 问题的解决方案。它没有回答“如何获取当前尝试次数”的问题。如果这是你想要的,请参见
使用工作过滤器和 OnStateApplied
回调:
public class CleanupAfterFailureFilter : JobFilterAttribute, IServerFilter, IApplyStateFilter
{
public void OnStateApplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
{
try
{
var failedState = context.NewState as FailedState;
if (failedState != null)
{
// Job has finally failed (retry attempts exceeded)
// *** DO YOUR CLEANUP HERE ***
}
}
catch (Exception)
{
// Unhandled exceptions can cause an endless loop.
// Therefore, catch and ignore them all.
// See notes below.
}
}
public void OnStateUnapplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
{
// Must be implemented, but can be empty.
}
}
将过滤器直接添加到工作函数中:
[CleanupAfterFailureFilter]
public static void MyJob()
或全局添加:
GlobalJobFilters.Filters.Add(new CleanupAfterFailureFilter ());
或者像这样:
var options = new BackgroundJobServerOptions
{
FilterProvider = new JobFilterCollection { new CleanupAfterFailureFilter () };
};
app.UseHangfireServer(options, storage);
或参阅 http://docs.hangfire.io/en/latest/extensibility/using-job-filters.html 了解有关职位筛选器的更多信息。
注意:这是基于已接受的答案:
不同之处在于使用了OnStateApplied
而不是OnStateElection
,所以只有在达到最大重试次数后才会调用过滤器回调。这种方法的缺点是无法中断状态转换为“失败”,但在这种情况下和大多数情况下都不需要这样做,您只想在作业失败后进行一些清理。
注意:空 catch
处理程序是不好的,因为它们可以隐藏错误并使它们难以在生产中调试。这是必要的,所以回调不会永远被重复调用。出于调试目的,您可能希望记录异常。还建议降低作业过滤器中出现异常的风险。一种可能性是,不是就地进行清理工作,而是安排一个新的后台作业,该作业在原始作业失败时运行。不过,请注意不要对其应用过滤器 CleanupAfterFailureFilter
。不要全局注册它,或者给它添加一些额外的逻辑...