Search code examples
asp.net-core-webapihangfire

Can Hangfire Work as A Simple Method Timer?


I have a .NET Core Web API application. The app contains models for db access and a way to send emails to users. My end goal is to call a method nightly (to email users that their registration expired and to mark it expired in the database).

So, in short, I can build an endpoint and call it manually every night. Or build a windows service to call the endpoint. Or build a windows service to do the work. But I want to keep the logic in one application.

My ideal solution would be to have a timer running inside my app and calling a method in a service every 24 hours. Of course, that's not possible, so I am looking at Hangfire. The official documentation seems to indicate that there is a lot of overhead.

Hangfire keeps background jobs and other information that relates to the processing inside a persistent storage. Persistence helps background jobs to survive on application restarts, server reboots, etc.

Do I need this if I just want to call a method?

Background jobs are processed by Hangfire Server. It is implemented as a set of dedicated (not thread pool’s) background threads that fetch jobs from a storage and process them. Server is also responsible to keep the storage clean and remove old data automatically.

Do I even need jobs?

Is there a way to JUST call a method without all this overhead with Hangfire?

tl;dr: Are there options to opt out of the dashboard, database connectivity, etc and just have Hangfire work as a timer?


Solution

  • My ideal solution would be to have a timer running inside my app and calling a method in a service every 24 hours. Of course, that's not possible...

    It's very possible, actually, using IHostedService. You should take some time to read the full documentation, but simply, for your scenario, you'd just need something like:

    internal class NightlyEmailHostedService : IHostedService, IDisposable
    {
        private Timer _timer;
    
        public Task StartAsync(CancellationToken cancellationToken)
        {
            _timer = new Timer(DoWork, null, TimeSpan.Zero, 
                TimeSpan.FromHours(24));
            return Task.CompletedTask;
        }
    
        private void DoWork(object state)
        {
            // send email
        }
    
        public Task StopAsync(CancellationToken cancellationToken)
        {
            _timer?.Change(Timeout.Infinite, 0);
            return Task.CompletedTask;
        }
    
        public void Dispose()
        {
            _timer?.Dispose();
        }
    }
    

    Then, in Startup.cs just add:

    services.AddHostedService<NightlyEmailHostedService>();
    

    Now, that's an extremely naive approach. It basically just kicks off a timer that will run once every 24 hours, but depending on when your app started, it may not always be at night. In reality, you'd likely want to have the timer run every minute or so, and check against a particular time you actually want the email to go out. There's an interesting implementation of handling cron-style times via an IHostedService you might want to reference.

    The long and short is that it's very possible to do this all in your app, without requiring anything additional like Hangfire. However, you have to a do a bit more work than you would have to using something like Hangfire, of course.