I’ve a solution with 3 projects:
- Service Class Library
- WebApi (is also the JobServer)
- Worker Client (Console Application)
Service class library has 2 classes:
IService.cs and Service.cs
public interface IService
{
[Queue("my_queue")]
[AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Fail)]
string Test(string input);
}
and
public class Service : IService, IDisposable
{
private readonly string _worker;
public Service(string worker)
{
_worker = worker;
}
public string Test(string input)
{
var message = string.Format("Worker: {0}, Task: {1}", _worker, input);
Console.WriteLine(message);
return message;
}
}
WebApi’s Startup is like:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
var service = new Service("WebApi");
services.AddInstance<IService>(service);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMvc();
var hostName = Configuration["Data:Hangfire.RabbitMQ:HostName"];
var dashboardPath = Configuration["Data:Hangfire.RabbitMQ:DashboardPath"];
var storage = new SqlServerStorage(Configuration["Data:Hangfire.Sql:ConnectionString"], new SqlServerStorageOptions { QueuePollInterval = TimeSpan.FromSeconds(1) });
storage.UseRabbitMq(conf => conf.HostName = hostName, new string[] { "my_queue" });
JobStorage.Current = storage;
var options = new BackgroundJobServerOptions();
options.ServerName = "WebApi";
options.Queues = new string[] { "my_queue" };
app.UseHangfireDashboard(dashboardPath);
app.UseHangfireServer(options, storage);
}
and I have a simple controller which basically creates 1000 jobs everytime I refresh the page:
[HttpGet]
public string Get()
{
for (var i = 1; i <= 1000; i++)
{
BackgroundJob.Enqueue<IService>(s => s.Test(i.ToString()));
}
return "1000 jobs enqueued";
}
and lastly; the worker client (Console application) is like:
static void Main(string[] args)
{
// Read Settings from App.config
var hostName = ConfigurationManager.AppSettings["Hangfire.RabbitMQ:HostName"];
var storage = new SqlServerStorage("Hangfire.Sql", new SqlServerStorageOptions { QueuePollInterval = TimeSpan.FromSeconds(1) });
storage.UseRabbitMq(conf => conf.HostName = hostName, new string[] { "my_queue" });
JobStorage.Current = storage;
var options = new BackgroundJobServerOptions();
options.ServerName = string.Format("Worker.{0}", args.Length > 0 ? args[0] : "Default");
options.Queues = new string[] { "my_queue" };
IService service = new Service(options.ServerName);
using (var server = new BackgroundJobServer(options, storage))
{
Console.WriteLine(string.Format("{0} started. Press any key to exit...", options.ServerName));
Console.ReadKey();
}
Environment.Exit(0);
}
Eventually, I run the web application and goto the hangfire subfolder to check the queue progress, and its full of following error;
System.MissingMethodException
Cannot create an instance of an interface.
System.MissingMethodException: Cannot create an instance of an interface.
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.Activator.CreateInstance(Type type)
at Hangfire.JobActivator.ActivateJob(Type jobType)
at Hangfire.Common.Job.Activate(JobActivator activator)
I am new to hangfire so may be missing something very trivial… Any thoughts?