How to run Hangfire custom jobs on another process?

Hi!

I have a use-case, which is covered very very little in your documentation (I have read all the docs, forums, google etc). I need to have two applications:

  • a web application which enqueues background jobs,
  • a console application
    The motivation is that I need to run very heavy DLLs, with a lot of dependencies and it’s not possible to add them to a IIS server.

What have I done?

  • took Hangfire.ConsoleApplication and Hangfire.MVCApplication from sample github (updated with hangfire 1.7.31)
  • delete line with app.UseHangfireServer() from Hangfire.MVCApplication (only Hangfire.ConsoleApplication has JobServer started)
  • from Hangfire.MVCApplication add job with BackgroundJob.Enqueue(() => Console.WriteLine("Background Job completed successfully!"));
  • in Hangfire.ConsoleApplication, in terminal, is written Background Job completed successfully
  • So, this simple example works (this is the example shown in your documentation)

But, I need from MVCApplication (the web interface) to enqueue only the name of the function and the body of the function should be implemented in ConsoleApplication, in order not to carry all heavy dependencies in IIS server.

What have I tried:

  • Attempt1:
    • in MVCApplication :
      BackgroundJob.Enqueue<IEmailSender>(x => x.Send("hangfire"));
interface IEmailSender{
         void Send(String s);
    }
    • in ConsoleApplication I defined IEmailSender and EmailSender
    • Error in ConsoleApplication in terminal: System.MissingMethodException Cannot create an instance of an interface.
  • Attempt2:

    • in MVCApplication :
      BackgroundJob.Enqueue<EmailSender>(x => x.Send("hangfire"));
public class EmailSender{
         public void Send(String s){ Console.WriteLine("BAD code from web {0}",s);
    }
    • in ConsoleApplication I defined EmailSender class:
public class EmailSender{
         public EmailSender() { }
         public void Send(String s){ Console.WriteLine("GOOD code from console {0}",s);
    }
    • in ConsoleApplication, Startup.cs I added:
      GlobalConfiguration.Configuration.UseDefaultActivator();
    • In ConsoleApplication, terminal: “BAD code from web hangfire”

So, it seems that ConsoleApplication is running the code pushed from MVCApplication (From your background-methods and getting-started docs), I understood that the code is not serialized)

Instead of calling the method immediately, Hangfire serializes the type (System.Console), method name (WriteLine, with all the parameter types to identify it later), and all the given arguments, and places it to Storage.

These lines use expression trees – not delegates like Action or Func<T> . And unlike usual method invocations, they are supposed to be executed asynchronously and even outside of the current process.

So, my question is how do I enqueue jobs only with the function name from MVCApplication, and the real implementation is done in ConsoleApplication?
If you have a real working example, I would appreciate.

Thank you.

We had the same requirements. We solved it by using kafka. web application enqueues job message in kafka. The consumer application, which in your case is the console app, registers consumers and receives message from kafka topic and starts job.

With this approach you can run multiple consumer apps against one hangfire server as well.

This is actually a well documented and common need.

Use dependency injection in hangfire to handle this situation. Google for that and you’ll see there are many good examples and this is well supported in hangfire. We do exactly what you described.

I run into the same problem and I searched hangfire DI with no luck. Can you provide an example ?

I have written two console applications. One with server and another with client and then ran two applications. However. Job from client is scheduled but is never executed by server. Am I doing anything wrong?