Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is an correct way to inject db context to Hangfire Recurring job?

I'm using HangFire to send emails to users in the background, regularly.

I'm obtaining email addresses from database, but I'm not sure whether I'm "injecting" database context to service that's responsible for sending emails correctly

This works correctly, is there a better way to do it?

public void Configure(IApplicationBuilder app, IHostingEnvironment env, Context context)
{
    (...)

    app.UseHangfireDashboard();
    app.UseHangfireServer(new BackgroundJobServerOptions
    {
        HeartbeatInterval = new System.TimeSpan(0, 0, 5),
        ServerCheckInterval = new System.TimeSpan(0, 0, 5),
        SchedulePollingInterval = new System.TimeSpan(0, 0, 5)
    });

    RecurringJob.AddOrUpdate(() => new MessageService(context).Send(), Cron.Daily);

    (...)
    app.UseMvc();
}

public class MessageService
{
    private Context ctx;

    public MessageService(Context c)
    {
        ctx = c;
    }

    public void Send()
    {
        var emails = ctx.Users.Select(x => x.Email).ToList();

        foreach (var email in emails)
        {
            sendEmail(email, "sample body");
        }
    }
}
like image 759
Joelty Avatar asked Nov 28 '18 08:11

Joelty


People also ask

How do I create a recurring job on hangfire?

Recurring job registration is almost as simple as background job registration – you need to write a single line of code, but you also need to specify an identifier you can use to refer to your job later. The call to AddOrUpdate method will create a new recurring job or update existing job with the same identifier.

How do I stop a recurring job on hangfire?

You can achieve this by using IMonitorinApi and fetch jobs that are processing. Then you can delete them by using IBackgroundJobClient. You need to pass in a cancellationtoken though.

How can we stop hangfire jobs?

There is no “Cancel” button for jobs in the built-in dashboard, only a “Delete” button. Using that Delete button will remove the Job from the running jobs in the built-in dashboard (near) instantly.

How do I track recurring jobs in Hangfire?

RecurringJob.AddOrUpdate("easyjob", () => Console.Write("Easy!"), Cron.Daily); This line creates a new entry in persistent storage. A special component in Hangfire Server (see Processing background jobs) checks the recurring jobs on a minute-based interval and then enqueues them as fire-and-forget jobs. This enables you to track them as usual.

Where are background jobs created in Hangfire?

Background jobs are created in a persistent storage – SQL Server, Redis, PostgreSQL, MongoDB and others . You can safely restart your application and use Hangfire with ASP.NET without worrying about application pool recycles.

How to handle exceptions and Hangfire retries?

You'd need to make sure you thought about exceptions and hangfire retries. One option is to turn off hangfire retries for the job, catch all exception and create a new job each time regardless of exception or not. What if service started executing the job and dies?

What is the Hangfire job delay?

On the Hangfire dashboard, we can see that the job is running with a delay of 20 seconds. The most used hangfire job type is Recurring Jobs. It is used so that the job can be run again in a certain time interval. For example, daily campaigns, Weekly total sales information, or monthly reports can be sent by mail using recurring jobs.


1 Answers

I just looked to the similar question and did not find the information in one place, so posting my solution here.

Assume you have your Context configured as a service, i.e.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    ....
    services.AddDbContext<Context>(options => { ... });
    ....
}

This makes the IServiceProvider capable to resolve the Context dependency.

Next, we need to update the MessageService class in order to not hold the Context forever but instantiate it only to perform the task.

public class MessageService
{
    IServiceProvider _serviceProvider;
    public MessageService(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public void Send()
    {
        using (IServiceScope scope = _serviceProvider.CreateScope())
        using (Context ctx = scope.ServiceProvider.GetRequiredService<Context>())
        {
            var emails = ctx.Users.Select(x => x.Email).ToList();

            foreach (var email in emails)
            {
                sendEmail(email, "sample body");
            }
        }
    }
}

And finally we ask Hangfire to instantiate the MessageService for us, it will also kindly resolve the IServiceProvider dependency for us:

RecurringJob.AddOrUpdate<MessageService>(x => x.Send(), Cron.Daily);
like image 170
Dmitry Mefed Avatar answered Oct 26 '22 23:10

Dmitry Mefed