如何在Hangfire中的后台作业中获取当前尝试号码?

Jim*_*mbo 6 asp.net-mvc scheduled-tasks hangfire

在我的Hangfire后台作业的最终尝试结束之前,我需要执行一些数据库操作(我需要删除与作业相关的数据库记录)

我当前的作业使用以下属性设置:
[AutomaticRetry(Attempts = 5, OnAttemptsExceeded = AttemptsExceededAction.Delete)]

考虑到这一点,我需要确定当前的尝试次数是什么,但我很难通过Google搜索或Hangfire.io文档找到这方面的任何文档.

Ols*_*dev 16

只需添加PerformContext到您的工作方法; 你也可以JobId从这个对象访问你.对于尝试号码,这仍然依赖于魔术字符串,但它比当前/唯一的答案更不稳定:

public void SendEmail(PerformContext context, string emailAddress)
{
    string jobId = context.BackgroundJob.Id;
    int retryCount = context.GetJobParameter<int>("RetryCount");
    // send an email
}
Run Code Online (Sandbox Code Playgroud)

  • 你如何将`PerformContext`传递给方法呢? (3认同)
  • @Alex Wiese https://github.com/HangfireIO/Hangfire/issues/806#issuecomment-276660621 (2认同)
  • 根据 @Olson.dev 链接:“...只需在作业定义中将其传递为 null,稍后它会自动替换为正确的实例。” (2认同)

Flo*_*ter 7

(注意!这是 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.
    }
}
Run Code Online (Sandbox Code Playgroud)

将过滤器直接添加到作业函数中:

[CleanupAfterFailureFilter]
public static void MyJob()
Run Code Online (Sandbox Code Playgroud)

或全局添加:

GlobalJobFilters.Filters.Add(new CleanupAfterFailureFilter ());
Run Code Online (Sandbox Code Playgroud)

或者像这样:

var options = new BackgroundJobServerOptions
{   
    FilterProvider = new JobFilterCollection { new CleanupAfterFailureFilter () };
};

app.UseHangfireServer(options, storage);
Run Code Online (Sandbox Code Playgroud)

或查看http://docs.hangfire.io/en/latest/extensibility/using-job-filters.html以了解有关作业过滤器的更多信息。

注意:这是基于接受的答案:https : //stackoverflow.com/a/38387512/2279059

不同之处在于OnStateApplied使用 代替OnStateElection,因此过滤器回调仅在最大重试次数后调用。这种方法的一个缺点是不能中断到“失败”的状态转换,但在这种情况下不需要这样做,并且在大多数情况下,您只想在作业失败后进行一些清理。

注意:空catch处理程序是不好的,因为它们可以隐藏错误并使它们难以在生产中调试。这里是必要的,所以回调不会永远被重复调用。您可能希望记录异常以进行调试。还建议降低作业过滤器中出现异常的风险。一种可能性是,不是在原地进行清理工作,而是安排一个新的后台作业,如果原始作业失败则运行该作业。但是,请注意不要对其应用过滤器CleanupAfterFailureFilter。不要全局注册它,或者给它添加一些额外的逻辑......


jta*_*loc 5

您可以使用OnPerformingOnPerformed方法IServerFilter,如果你要检查的尝试,或者如果你愿意,你可以只是等待OnStateElectionIElectStateFilter.我不知道你有什么要求,所以这取决于你.这是你想要的代码:)

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.            
        }
    }   
}
Run Code Online (Sandbox Code Playgroud)

如何添加过滤器

GlobalJobFilters.Filters.Add(new JobStateFilter());

----- or 

var options = new BackgroundJobServerOptions
{   
    FilterProvider = new JobFilterCollection { new JobStateFilter() };
};

app.UseHangfireServer(options, storage);
Run Code Online (Sandbox Code Playgroud)

样本输出:

在此输入图像描述

  • 依靠文本充其量只是hackish ......,随时可能会破坏......但这总比没有好......谢谢! (2认同)