Search code examples
c#webapihangfire

Hangfire RecurringJob "does not contain a method with signature"


I am using Hangfire configured in my WebAPI .NET Framework 4.7.2 application. I am configuring it inside the Global.asax.cs My dependency injection chain is configured using Autofac.

This is the way I am calling the recurring job

RecurringJob.AddOrUpdate<RunnerClass>(nameof(RunnerClass.MyMethod)+"_"+DateTime.UtcNow.ToString("yyMMddHHmmss"), r => r.MyMethod(), "* * * * *", queue: "specialqueue");

I am trying to make sure that this is delivered to a special queue that only my local application is listening to, to avoid other servers from picking this task up. Also, my task name is unique every time I fire up the WebAPI project to avoid picking up some old dll cache (not sure if this is possible)

My MyMethod implementation is as follows:

public class RunnerClass
{
     public RunnerClass(IDependenciesInjectedByAutofac dependency){
         //do something with dependencies
     }

     public string MyMethod(){
        // perform database calls to a database NOT the same where Hangfire schema lives
        // log some stuff to Cloud Provider
      var storeList = new List<Guid>();
       Parallel.ForEach(listOfGuids, g => { storeList.Add(MySubMethod(g)); }
       //some more DB stuff and logging
      return "finished";
     }

     public Guid MySubMethod(Guid guid){
      // do DB stuff
     }
}

This DOES NOT WORK. I get the following exception when running.

System.InvalidOperationException: Recurring job can't be scheduled, see inner exception for details. ---> Hangfire.Common.JobLoadException: Could not load the job. See inner exception for the details. ---> System.InvalidOperationException: The type MyNamespace.RunnerClass does not contain a method with signature MyMethod() at Hangfire.Storage.InvocationData.DeserializeJob() --- End of inner exception stack trace --- at Hangfire.Storage.InvocationData.DeserializeJob() at Hangfire.RecurringJobEntity..ctor(String recurringJobId, IDictionary`2 recurringJob, ITimeZoneResolver timeZoneResolver, DateTime now) --- End of inner exception stack trace --- at Hangfire.Server.RecurringJobScheduler.ScheduleRecurringJob(BackgroundProcessContext context, IStorageConnection connection, String recurringJobId, RecurringJobEntity recurringJob, DateTime now)

Now, this does not occur when I try to run normally using BackgroundJob instead of RecurringJob. This is very weird, since I am 100% no other instance is picking up my job. Also worth saying that sometimes if I add a breakpoint inside the function invocation it works. Building the function from scratch allows me to add the recurring job, but suddenly it stops working without any apparent reason...

EDIT It looks like cleaning the bin and obj directories works, until it just does not...

Is there something wrong in my invocation? I have tried to remove the Parallel.ForEach, but to no avail.


Solution

  • While the job is being executed from the worker that is listening on a specific queue; only this worker needs the implementation. But creating (and enqueuing) a job from a recurring entry will be done by any Hangfire server. And this is what currently is failing. To avoid this problem, create a separate project that contains only a matching interface for your method and add this interface project to all your servers and within the recurring job creation call, also only use this interface.

    Within your server listening on your special queue, register your implementation within the DI framework, so your local Hangfire worker knows what to pick to instantiate a class for the given interface.

    By this approach every server can create/enqueue the job, but it will be processed only be the worker who is listening on the defined queue name.