Anthony Frasso
Anthony Frasso

Reputation: 109

How do I execute a new job on success or failure of Hangfire job?

I'm working on a Web API RESTful service that on a request needs to perform a task. We're using Hangfire to execute that task as a job, and on failure, will attempt to retry the job up to 10 times.

If the job eventually succeeds I want to run an additional job (to send an event to another service). If the job fails even after all of the retry attempts, I want to run a different additional job (to send a failure event to another service).

However, I can't figure out how to do this. I've created the following JobFilterAttribute:

public class HandleEventsAttribute : JobFilterAttribute, IElectStateFilter
{
    public IBackgroundJobClient BackgroundJobClient { get; set; }

    public void OnStateElection(ElectStateContext context)
    {
        var failedState = context.CandidateState as FailedState;
        if (failedState != null)
        {
            BackgroundJobClient.Enqueue<MyJobClass>(x => x.RunJob());
        }
    }
}

The one problem I'm having is injecting the IBackgroundJobClient into this attribute. I can't pass it as a property to the attribute (I get a "Cannot access non-static field 'backgroundJobClient' in static context" error). We're using autofac for dependency injection, and I tried figuring out how to use property injection, but I'm at a loss. All of this leads me to believe I may be on the wrong track.

I'd think it would be a fairly common pattern to run some additional cleanup code if a Hangfire job fails. How do most people do this?

Thanks for the help. Let me know if there's any additional details I can provide.

Upvotes: 2

Views: 7375

Answers (2)

Anton Anpilogov
Anton Anpilogov

Reputation: 141

Hangfire can build an execution chains. If you want to schedule next job after first one succeed, you need to use ContinueWith(string parentId, Expression<Action> methodCall, JobContinuationOptions options); with the JobContinuationOptions.OnlyOnSucceededState to run it only after success.

But you can create a HangFire extension like JobExecutor and run tasks inside it to get more possibilities.

Something like that:

public static JobResult<T> Enqueue<T>(Expression<Action> a, string name)
{
    var exprInfo = GetExpressionInfo(a);

    Guid jGuid = Guid.NewGuid();

    var jobId = BackgroundJob.Enqueue(() => JobExecutor.Execute(jGuid, exprInfo.Method.DeclaringType.AssemblyQualifiedName, exprInfo.Method.Name, exprInfo.Parameters, exprInfo.ParameterTypes));            

    JobResult<T> result = new JobResult<T>(jobId, name, jGuid,  0, default(T));
    JobRepository.WriteJobState(new JobResult<T>(jobId, name, jGuid, 0, default(T)));

    return result;
}

More detailed information you can find here: https://indexoutofrange.com/Don%27t-do-it-now!-Part-5.-Hangfire-job-continuation,-ContinueWith/

Upvotes: 2

Steve
Steve

Reputation: 634

I haven't been able to verify this will work, but BackgroundJobClient has no static methods, so you would need a reference to an instance of it.

When I enqueue tasks, I use the static Hangfire.BackgroundJob.Enqueue which should work without a reference to the JobClient instance.

Steve

Upvotes: 0

Related Questions