[AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Fail)] is not working

Hi,

[AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Fail)] is not working.
On exception in my job it goes to schedule state and then Retry attempts happens !!!

I tried wiriting this attribute on controller and business class methods and thrown exception from data access layer method but in state table it shows retry attempts.

Please do the needful asap.

I have the same problem. I get a warning like “Error occurred during execution of ‘Worker #9’ component. Execution will be retried (attempt 1 of 2147483647) in 00:00:00 seconds.”

I seem to be having the same problem. Is there a way around this? I REALLY need the job to only be run once.

I see the same issue. I see it with Recurring Jobs (only type I’m using). Using Hangfire 1.4.6.

I was able to resolve my issue. I had a custom Filter; that was throwing an exception. This apparently aborted the normal processing of jobs, and caused the ‘attempt 1 of 2147483647’ problem, etc…

I have marked my job classes also I tried it by marking the method but the attribute is being ignored, the global filter works fine if I use

GlobalJobFilters.Filters.Add(new AutomaticRetryAttribute { Attempts = 0 });

Just confused as to why the class\method attribute below is not working.

[AutomaticRetry(Attempts = 0, LogEvents = true)] is being ignored?

I’ve run into a similar issue recently. I’ve posted my solution on stackoverflow (https://stackoverflow.com/a/45859845/1104481). Anyway, my solution is the following:

I’m using asp.net core and I have a simple fire and forget background job. Using a global filter was not an option for me. For some reason the AutomaticRetryAttribute was being ignored. It turned out the way I was adding the job was the key to my solution. I had a similar code in my app that was causing the issue:

BackgroundJob.Enqueue<IMyJobService>(js => js.DoWork());

In my IMyJobService implementation I had the following code:

[AutomaticRetry(Attempts = 0)]
public void DoWork()
{
    // I'm working hard here
}

The solution that I came up with was:

public MyTestController
{
    private readonly IMyJobService _myJobService;
    
    public MyTestClass(IMyJobService myJobService)
    {
        _myJobService = myJobService;
    }
    
    public ActionResult Work()
    {
        BackgroundJob.Enqueue(() => _myJobService.DoWork());
        return Ok();
    }
}

Instead of relying on BackgroundJob.Enqueue<T> to inject my IMyJobService implementation I do it myself. That’s basically it. I hope this will help someone.

@dynamiclynk are you running on .NET Core? There’s a bug with attribute-based filters there.

Yep I am using .net core 1.1 so that must be the issue. Thank you.

Refer to https://github.com/HangfireIO/Hangfire/issues/799 for the temporary workaround :slight_smile:

Most likely it’s not a ‘bug’ with attribute based filters causing this. If you’re using a DI container with an interface (like the following) then you must put the hangfire attributes on the interface and not the implementation.

Hangfire.RecurringJob.AddOrUpdate(updater => updater.UpdateGen2Data(), Cron.Hourly);

public interface IDataUpdater
{
[Hangfire.AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
void UpdateData();
}

2 Likes

This is correct. Interface works while implementation does not.

Hi,
I am using ASP.NET Core 2.2 and one of my jobs is decorated with

public interface IGenerateSurveyJob
{
    [AutomaticRetry(Attempts = 1, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
    Task Generate(long orderId);
}

Hangfire ignores the Attribute: there are still 10 retries and after that, the Job is failed and not deleted.

Any ideas?
Thanks

Ironically, it works for me if I decorate also the implemented method
,
public class GenerateSurveyJob : IGenerateSurveyJob
{
[AutomaticRetry(Attempts = 1, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
public async Task Generate(long orderId)
{
… lots of stuff …
}
}

I wanted to chime in and say I also had to put it on the implementation and NOT the interface. Core 2.2

You have to put it in the implementation and NOT in the interface.