In HangFire, can I Enqueue with a queue name instead of using the Queue attribute?
Asked Answered
C

3

21

This documentation says that you can specify a queue by using the Queue attribute on the method to be invoked. This assumes that you always want execute a method on the same queue. Is there a way for the process that calls Enqueue to specify the name of the queue to put the job into (effectively putting the decision-making in the hands of the job generator, not the definition of the job).

Cousingerman answered 23/4, 2015 at 13:27 Comment(0)
N
20

With a instance of IBackgroundJobClient you can specify a queue.

IBackgroundJobClient hangFireClient = new BackgroundJobClient();
EnqueuedState myQueueState = new Hangfire.States.EnqueuedState("myQueue");
hangFireClient.Create<SomeClass>(c => c.SomeMethod(), myQueueState);

Note that in this way, a retry will put the job back to the default queue. You will require additional code to retry in the same queue, using a JobFilter

http://discuss.hangfire.io/t/one-queue-for-the-whole-farm-and-one-queue-by-server/490/3

Novobiocin answered 29/5, 2015 at 13:14 Comment(4)
I've tried that but it gives me "Cannot create an instance of an inteface" despite using the ...Create<IFoo>(x=>x.Bar(), myQueueState). Any idéas?Bogie
Probably missing the Dependency Inject Resolver, but i'm guessing by now you already fix your issue. Sorry, didnt see your question sooner.Novobiocin
Worked for me. The class and method cannot be static, but it works fine.Homophile
This works. Something to note is, if your method throws an exception while processing, Hangfire will requeue it to a "default" queue (unless you specify a queue through an attribute).Joacima
F
9

If you want to change the queue Dynamically you can follow this way.

This implementation works for all Enqueue, Schedule and ContinueJobWith

Version 1.7.X onwords

public class HangfireDynamicQueue
{
    public void EnqueJobs()
    {
        // Enqueue "MyBackgroundJob1" under "default" queue
        var job1 = BackgroundJob.Enqueue("default",() => MyBackgroundJob1(123));

        // Enqueue "MyBackgroundJob1" under "critical" queue
        var job2 = BackgroundJob.Enqueue("critical", () => MyBackgroundJob1(345));

        // Execute "MyBackgroundJob1" after 10 seconds under "delayed" queue
        var job3 = BackgroundJob.Schedule("delayed", () => MyBackgroundJob1(567), TimeSpan.FromSeconds(10));

        // Run "MyBackgroundJob2" after job3 under "continue" queue
        var job4 = BackgroundJob.ContinueJobWith(job3, "continue", () => MyBackgroundJob2(789));
    }

    public void MyBackgroundJob1( int arg)
    {
        // Job implementation
    }

    public void MyBackgroundJob2(int arg)
    {
        // Job implementation
    }
}

Before version 1.7.X - Outdated

This implementation works for all Enqueue , Schedule and ContinueJobWith

The trick happen on [Queue("{0}")]. Hangfire will pass job arguments to the given pattern ("{0}") using String.Format("{0}", job.Args) to get the actual queue on every state change, so the target queue will be applied even for retries.

Highlighted Code Syntax :

// Enqueue "MyBackgroundJob1" under "critical" queue
var job2 = BackgroundJob.Enqueue(() => MyBackgroundJob1("critical", 523));

// Use one of following Attributes depending on your hangfire version
//[AdvancedQueue("{0}")] //  1.6.X 
[Queue("{0}")] // In 1.7.X
public void MyBackgroundJob1(string queueName, int arg)
{
    // Job implementation
}

Full Implementation :

public class HangfireDynamicQueue
{
    public void EnqueJobs()
    {
        // Enqueue "MyBackgroundJob1" under "default" queue
        var job1 = BackgroundJob.Enqueue(() => MyBackgroundJob1("default", 123));

        // Enqueue "MyBackgroundJob1" under "critical" queue
        var job2 = BackgroundJob.Enqueue(() => MyBackgroundJob1("critical", 523));

        // Execute "MyBackgroundJob1" after 10 seconds under "delayed" queue
        var job3 = BackgroundJob.Schedule(() => MyBackgroundJob1("delayed", 678), TimeSpan.FromSeconds(10));

        // Run "MyBackgroundJob2" after job3 under "delayed" queue
        var job4 = BackgroundJob.ContinueJobWith(job3, () => MyBackgroundJob2("delayed", 435));
    }

    // Use one of following Attributes depending on your hangfire version
    //[AdvancedQueue("{0}")] //  1.6.X 
    [Queue("{0}")] // In 1.7.X
    public void MyBackgroundJob1(string queueName, int arg)
    {
        // Job implementation
    }

    // Use one of following Attributes depending on your hangfire version
    //[AdvancedQueue("{0}")] //  1.6.X 
    [Queue("{0}")] // In 1.7.X
    public void MyBackgroundJob2(string queueName, int arg)
    {
        // Job implementation
    }
}
Freshet answered 18/8, 2021 at 16:54 Comment(2)
This is an underrated hack. I'm disappointed in the hangfire team for not implementing this on "BackgroundJobClient" level at least.Lund
Version 1.7.X onwards, this feature comes with the library, no more a hack :)Freshet
W
2

Since adding an extra parameter seems to be so hard for the Hangfire team ;-)....

...I've found the most convenient way is to make two methods that just call the actual implementation, and put different [Queue] attributes on each.

Usually if I need to switch queues it's between dev / production and I want to just call something like RunOrder(...) with isTestOrder=boolean and not be concerned about queues at that level.

public void RunOrder(int orderId, bool isTestOrder) 
{
   if (isTestOrder) 
   {
      BackgroundJob.Enqueue(() => _RunTestOrder(orderId));
   } 
   else 
   {
      BackgroundJob.Enqueue(() => _RunOrder(orderId));
   }
}

[Queue("dev")]
public void _RunTestOrder(int orderId) {
  OrderProcessor.RunOrder(orderId); // actual code to call processor
}

[Queue("production")]`
public void _RunProductionOrder(int orderId) {
  OrderProcessor.RunOrder(orderId); // is the same in both 'hangfire proxies'
}

Note usage of _ to indicate these aren't meant to be called directly. I don't remember off hand if hangfire methods need to be public or not - but if they do need to be then the _ is more important.

Willowwillowy answered 3/2, 2019 at 22:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.