Hangfire.MAMQSqlExtension
Hangfire.MAMQSqlExtension copied to clipboard
MAMQSqlServerStorage doesn't implement Hangfires new HasFeature method introduced with 1.8.0
Background / Steps to reproduce
I have the following setup:
- An ASP.NET Core web application running with .NET 6.
- Hangfire with the latest version 1.8.9
- MAMQSqlExtension with the latest version 1.0.6 to support multiple Hangfire instances to use one single MS SQL database.
A usage within our application is to schedule a background job with a predefined delay. This job should be scheduled in a specific queue, let's name it "queue1". To schedule this job, we use one of the methods provided by the BackgroundJob class, but you can use any other method that is offered by Hangfire to schedule a job for a specific queue. Now we want to schedule this job by using the BackgroundJob.Schedule
method, but we want to use the overload that accepts the queue name as parameter. An example would be:
BackgroundJob.Schedule("queue1", () => Console.WriteLine("Hello World!"), TimeSpan.FromMinutes(1));
The Problem
The above example leads to the following exception:
---> Hangfire.BackgroundJobClientException: Background job creation failed. See inner exception for details. ---> System.NotSupportedException: Current storage doesn't support specifying queues directly for a specific job. Please use the QueueAttribute instead.
This is caused by the fact that MAMQSqlExtension is set to the Hangfire.SqlServer package version 1.7.11. If you want to use a newer Hangfire version as 1.7.11, you will be unable to use it with the current latest version of MAMQSqlExtension and by injecting the queue name as a parameter to the method.
With Hangfire 1.8.0 the JobStorage class introduced a new method called HasFeature. This method is used to evaluate if the underlying storage supports several features, in our case the feature to inject the queue name as method parameter.
Solution 1 - Downgrade to a lower Hangfire version and stick with it
A quick solution is to downgrade to a version below 1.8.x to get MAMQSqlExtension and Hangfire running. This results in the consequence that you are forced to stay on a specific version of Hangfire to use MAMQSqlExtension, but this is not an appropriate solution for the future.
Solution 2 - Use default queue
Another way to get around this error is to use the BackgroundJob.Schedule
method without the queue name parameter, which results in Hangfire to schedule this job on the default queue. This is not a proper solution for our use case, because we want to schedule this job in a dedicated queue and not lose the functionality of MAMQSqlExtension.
Solution 3 - Use the Queue / RetryInQueue attribute
This would require the code to be rewritten to something like:
public class MyJob
{
public void ScheduleJob() => BackgroundJob.Schedule(() => this.ExecuteJob(), TimeSpan.FromMinutes(1));
[RetryInQueue("Queue1")
public void ExecuteJob() => Console.WriteLine("Hello World");
}
This leads to more boilerplate code just to get MAMQSqlExtension running with the newest Hangfire version, which is not our preferred solution, but for now it fits to our use case. If it's possible to schedule jobs to Hangfire with the Expression<T>
-syntax, we would prefer it over the solution with the attribute.
Solution 4 - Update the dependency of Hangfire within MAMQSqlExtension and implement the HasFeature method
This requires to drop the support for Hangfire versions below 1.8.0, but enables a proper usage of MAMQSqlExtension with newer Hangfire versions. The required modification for the MAMQSqlServerStorage to make, looks like the following:
public class MAMQSqlServerStorage : JobStorage
{
[...]
public overwrite bool HasFeature([NotNull] string featureId)
{
if (featureId == null)
{
throw new ArgumentNullException(nameof(featureId));
}
return _inner.HasFeature(featureId);
}
}
You can probably remove the check of the featureId
parameter, because this check will also be made in the underlying SqlServerStorage.
Conclusion
It would be good if we can find a good solution to support this functionality. I'm willing to implement the chosen solution as a PR back to this repository.
I hope to get a response from you @GeXiaoguo and find a solution for this problem. If there are any outstanding questions from your side, please don't hesitate to contact me.
Best regards Philip / Zeruxky