For .NET environment sometimes you need some scheduler process for recurring jobs. Most popular schedule tools are Quartz and Hangfire.

Before, I had used Quartz in my some projects but after introduced with Hangfire, it completely changed my mind. Hangfire is open and free for commercial use. And one of my project I used Hangfire and you can see the difference between these two tools when you experience both of them. With Hangfire all database management is handled by itself. It creates all related tables as job histories, job definitions etc. automatically.

Hangfire tables

So it makes your jobs very easy. And it provides a dashboard for you to see the jobs details and manage these jobs as delete, update etc.

Hangfire Dashboard

Also Hangfire makes the test easy with its mock library. You can mock Hangfire by using Hangfire mock and Hangfire MemoryStorage for mocking db processes .

Hangfire Dashboard

I will share you my project created by using with .Net6 and Hangfire. Lets jump to code a little bit;

Lets start adding Hangfire to project;

First add Hangfire from Nuget and add your project as below;



service.AddHangfire(config =>
            {
                var options = new SqlServerStorageOptions
                {
                    PrepareSchemaIfNecessary = true;
                    CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
                    SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
                    UseRecommendedIsolationLevel = true,
                    UsePageLocksOnDequeue = true,
                    DisableGlobalLocks = true
                };

                config.UseSqlServerStorage(configuration.GetConnectionString("DefaultConnection"), options).WithJobExpirationTimeout(TimeSpan.FromHours(6));
            });



To use Hangfire dashboard you should add it to project startup;



app.UseHangfireDashboard(
                "/hangfire", new DashboardOptions
                {
                    DashboardTitle = "Health Checker Hangfire Dashboard",
                    AppPath = "https://localhost:44338/jobs", 
                    Authorization = new[] { new HangfireCustomBasicAuthenticationFilter{
            User = hangfireSettings.Username,
            Pass = hangfireSettings.Password
        } } 
                
		});

And to run Hangfire server add ;



app.UseHangfireDashboard(
                "/hangfire", new DashboardOptions
                {
                    DashboardTitle = "Health Checker Hangfire Dashboard",
                    AppPath = "https://localhost:44338/jobs", 
                    Authorization = new[] { new HangfireCustomBasicAuthenticationFilter{
            User = hangfireSettings.Username,
            Pass = hangfireSettings.Password
        } } 
                
			});

Add Retry number when a schedule failed;



 GlobalJobFilters.Filters.Add(new AutomaticRetryAttribute { Attempts = 7 });

Thats all for startup. I will share only ScheduleService to show how to CRUD a hangfire job. More is on github link;



public class ScheduleJobManager<T> : IScheduleJobManager<T> where T : IJob
    {
        public void AddJob(string jobName, int jobId, int interval, IntervalEnum intervalType)
        {
            RecurringJob.AddOrUpdate<T>(jobName, j => j.Process(jobId), GetCronFromInterval(interval, intervalType));
        }

        public void DeleteJob(string jobName)
        {
            RecurringJob.RemoveIfExists(jobName);
        }

        public void UpdateJob(string oldJobName, string jobName, int jobId, int interval, IntervalEnum intervalType)
        {
            RecurringJob.RemoveIfExists(oldJobName);
            RecurringJob.AddOrUpdate<T>(jobName, j => j.Process(jobId), GetCronFromInterval(interval, intervalType));
        }

        private string GetCronFromInterval(int interval, IntervalEnum intervalType)
        {
            var result = intervalType switch
            {
                IntervalEnum.Minute => Cron.MinuteInterval(interval),
                IntervalEnum.Hour => Cron.HourInterval(interval),
                IntervalEnum.Day => Cron.DayInterval(interval),
                IntervalEnum.Week => Cron.Weekly(),
                IntervalEnum.Month => Cron.MonthInterval(interval),
                _ => throw new NotImplementedException()
            };
            return result;
        }
    }

Github Link

Thanks for reading. See you soon 😄