Fail a job with conditional retry


#1

I have a job that could fail for a number of reasons.
In some cases I do not want to retry the job at all but in others I do.

Note that I do not want to use the AutomaticRetry attribute (as far as I am aware) because this would retry my job N times for any failure.

Is it possible to fail a job and indicate to Hangfire that it should not be retried?


To give more context I am performing some DB lookups and if one of those fails I do not want to retry. But if there were, for example, a network failure later on in the job I do want to retry.

Edit: I am using Hangfire 1.6.20 with ASP.NET Core 2.1.3


#2

Yes, sure you can.

I do use something like this on my projects…

I don’t remember since which version it was available, but, on the current versions there is the PerformContext that you can inject in your jobs. It will allow you to access the running job context.

Just put it as a parameter in your job method, then, when queuing or scheduling the job, just pass null in it’s place, it will be injected upon job starts… (Don’t know if it requires any external activator, 'cos in all projects that i ever used hangfire, it was using Dependency Injection through some IoC Container).

Then, with the PerformContext instance inside your job, you can conditionally exhaust your job retries achieving the behavior that you want, so, you still can use the AutomaticRetryAttribute alongside with this…

To do this you may set the job RetryCount parameter to a number higher than your system ever could use… ex: 9999.

So, for example:

public class DummyJobsClass{
	// A RetryCount number that your system should never allow!
	public const int ExhaustRetryCounts = 9999;
	
	[AutomaticRetry(Attempts = 10)]
	public void MyDummyJobMethod(Guid someArgument, string anotherOne, PerformContext performContext){
		
		// ...

		if(true == SomeConditionThatJobMustNotRetry){
			// Set the job RetryCount to a Number that is 'Never Allowed' in your system...
			performContext.SetJobParameter("RetryCount", ExhaustRetryCounts);
			// Throw some exception to exit the Job and have a nice reason on your Dashboard... 
			throw new Exception("Houston, we have found an Alien! Never get back here!");
		}

		// ...
	}
}

Hope it helps…

Ahh one last tip:
_To be easy, and improve readability, i do use an Extension Method created in my projects on the PerformContext type, nicelly called ExaustJobRetries accepting a Reason parameter… _


#3

Thanks a ton for your feedback and solution, I’ll give that a go!

One thing about your solution that I do not fully understand is… won’t this job just be retried 9999 times then since we have now set the RetryCount to that number?


#4

No, before retrying a job, hangfire Will look at this parameter, and, If it’s greater than the Attempts It won’t reenqueues It. So, It does not need to be 9999 Just greater than the Attempts n°. But, as i do use a helper for the entire project, i do choose a value that i would never use at Attempts. :sunglasses:


#5

For clarification, hangfire increments this parameter in every retry attempt, starting from 0 (the default, as it’s not present on the parameters collection in the very first run…, if It fails, and the job should be retried, It Will be set to 1 when being reenqueued, and so on…)


#6

That makes sense. Thanks a ton for your help @LucasPereira!