I’m currently trying to setup HangFire and I have the axd part working in an MVC5 app. I’ve also set it up with a SQL Server database and this is registering, with the console showing.
When I used the AspNetBackgroundJobWorker in that app, the worker registers itself and shows up in the admin UI.
But when I create a console app and run it, it just exits. It’s able to connect to the database because I can enqueue jobs. But it doesn’t dequeue, or appear as a server/worker pool in the UI.
Also the console app exits immediately.
Here’s the code for the console app:
static void Main(string[] args)
{
JobStorage.Current = new SqlServerStorage("BackgroundDB");
BackgroundJob.Enqueue(() => Console.WriteLine("Hello, world!"));
var server = new BackgroundJobServer();
server.Start();
}
I did this because I initially tried this as a Windows Service and had the same issue, using this code:
public partial class BackgroundWorker : ServiceBase
{
private static BackgroundJobServer _server;
private Task _backgroundServerTask;
public BackgroundWorker()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
_backgroundServerTask = Task.Run(() =>
{
_server = new BackgroundJobServer(new BackgroundJobServerOptions(), new SqlServerStorage("BackgroundDB"));
_server.Start();
});
}
protected override void OnStop()
{
_server.Stop();
_backgroundServerTask.Wait();
}
}
Yep, this is because the Start method is non-blocking and it only creates a separate background thread to perform all the processing work. Non-blocking semantic allows this method to be used inside ASP.NET application. If you want to block the console application, you can simply add the following line (do not forget to call the Dispose method for a graceful shutdown, or use the using statement):
static void Main(string[] args)
{
JobStorage.Current = new SqlServerStorage("BackgroundDB");
BackgroundJob.Enqueue(() => Console.WriteLine("Hello, world!"));
using (var server = new BackgroundJobServer())
{
server.Start();
Console.WriteLine("HangFireServer started. Press ENTER to stop the processing...");
Console.ReadLine();
}
}
The following service class works fine for me after adding installer and installing windows service via installutil.exe program.
public partial class HangFireService : ServiceBase
{
private BackgroundJobServer _server;
public HangFireService()
{
InitializeComponent();
JobStorage.Current = new SqlServerStorage(
@"Server=.\sqlexpress; Database=HangFire.Sample; Trusted_Connection=True;");
}
protected override void OnStart(string[] args)
{
_server = new BackgroundJobServer();
_server.Start();
}
protected override void OnStop()
{
_server.Stop();
}
}
If you want to simplify the debugging of Windows Service, look at TopShelf project.
Thanks! The advice for the console worked perfectly.
But using your code, I still wasn’t able to get it working as a service. I’ll try TopShelf. Any reason why people shouldn’t use a service? Seems like a console app would be unstable and wouldn’t automatically start on restart, etc.
I did install it and was able to hit “start”, and then it says it took too long to start.
I have multiple web servers and would like to decouple the background workers from that. Currently we are using Amazon Web Services SQS for queueing but probably can’t do that here.
I should consider the ASP.NET background worker actually… our web servers are using 5% CPU
Check the Control Panel / Administrative tools / Event log, perhaps it contains an error with exception, perhaps with SqlException, perhaps about your Network Service, Local System or other entity does not have access to the database.
If your background tasks are consume only I/O (sending mail, web service calls, etc), you can leverage existing apps – HangFire works well in web farm environment. But if your jobs consume too much CPU and you want to process requests, you should use windows services (or create a PR for a setting worker thread priority feature ).