.OnFinalFailure(...) option

It would be nice if we could queue up a task to run when a job fails on its 10th retry (or last depending on retry settings)

So instead of monitoring for specific job type in a job filter (http://stackoverflow.com/questions/33703661/how-do-i-execute-a-new-job-on-success-or-failure-of-hangfire-job) you could assign a method to run upon final failure.

Enqueue(…).OnFinalFailure(…)

We have some jobs we queue up during a work flow event, however if a critical part fails we roll back the item to a different status and notify some parties. Its easy enough to try/catch log/notify on each failure within job and then throw the exception so HangFire retries but it gets much messier to catch the error on last job try and take action. I suppose another option on this would be to get a jobstate passed into a job where we could check something like IsFinalTry

2 Likes

I like this idea.

I’ve resorted to scheduling a job processes my jobs that have failed using Hangfire.JobStorage.Current.GetMonitoringApi().FailedJobs(start,count). It’s not ideal, but gets the job done for me. This gives you All the information of the job, and the exception types and details.

Alternatively, you could use BackgroundJob.ContinueWith("jobid", () => MyFollowupMethod(myownDto), JobContinuationOptions.OnAnyFinishedState); This would work if from your parameters, you can determine if the thing you’re working on is in a failed state.

Or you could go at it another way, pass the job id in to your follow up method and check if the job is failed, and why. BackgroundJob.ContinueWith(enQueuedJobId, () => MyFollowupMethod(enQueuedJobId), JobContinuationOptions.OnAnyFinishedState);

Perhaps it is a bug, however ContinueWith does not fire, even with OnAnyFinishedState if the parent job failed.

I have tried many things to determine final failure - and all ended in failure. Hangfire is missing this crucial state.

I have attempted to tie into OnStateElection, however Hangfire will elect a failed state only to reschedule it again (if max attempts has not been reached) therefore that solution cannot work.

I have attempted the solution above however it does not queue - only sits at awaiting with ‘parent failed’
BackgroundJob.ContinueWith(scheduleTaskKey, () => new Temporary().Execute(scheduleTaskKey), JobContinuationOptions.OnAnyFinishedState);

I will attempt to create a RecurringJob in order to find any failed tasks, do what I need to do with them, then set them to deleted status however I feel this would be a very important feature.

Hi,

I know this is an old post, but since it came up while trying to find a solution I thought it would be helpful for others to see the solution I’ve found. You need to use the OnStateApplied not the OnStateElection if you want to only catch the last failure:

using Hangfire.Common;
using Hangfire.States;
using Hangfire.Storage;

namespace App.Services
{
  public class EmailFailuresAttribute : JobFilterAttribute, IApplyStateFilter
  {
    public void OnStateApplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
    {
      // Unlike IElectStateFilter.OnStateElection, this function only gets called with a failed status after
      // all retries have been used up
      var failedState = context.NewState as FailedState;

      if (failedState != null)
      {
        // TODO - Add Email Code
      }
    }

    public void OnStateUnapplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
    {
      // Required to match IApplyStateFilter
    }
  }
}

using App.Services;
using Hangfire;
using Hangfire.Server;
using System.Threading.Tasks;

  public interface IHangFireJobs
  {
    // Annotations needs to be on the interface not the implementation
    // if job scheduling is done using interface
    [EmailFailures]
    [AutomaticRetry(Attempts = 2, OnAttemptsExceeded = AttemptsExceededAction.Fail
	, DelaysInSeconds = new int[2] { 3, 6 })]
    Task SomeJob(PerformContext context);

  }
1 Like