2

I'm working on an ASP.NET web application written in C# and hosted in an Azure virtual machine using IIS 10 as a web server. I have to schedule a background task to run once a day. To achieve this I created the following DailyTask class:

public class DailyTask : IHostedService {

    public Task StartAsync(CancellationToken cancellationToken) {
        Debug.WriteLine("start");
        Task.Run(TaskRoutine, cancellationToken);
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken) {
        Debug.WriteLine("stop");
        return null;
    }

    public Task TaskRoutine() {
        while (true) {
            try {
                /* ... */

                DateTime nextStop = DateTime.Now.AddDays(1);
                var timeToWait = nextStop - DateTime.Now;
                var millisToWait = timeToWait.TotalMilliseconds;
                Thread.Sleep((int)millisToWait);
            }

            catch (Exception e) {
                Debug.WriteLine(e);
            }
        }
    }
}

To start this task I added the following statement in my Startup class:

public class Startup {
    public void ConfigureServices(IServiceCollection services) {
        /* ... */
        services.AddSingleton<Microsoft.Extensions.Hosting.IHostedService, HiddenUserCleaner>();
        /* ... */
    }
}

After a deploy on my test server, I observed that this solution works fine. But is it reliable? Can there be problems if used in production?

El_Merendero
  • 603
  • 3
  • 14
  • 28
  • What you attempted to do is similar to using a framework like Hangfire, so it suffers the same issues, and you should go back and check out alternatives. I shared some hints in https://blog.lextudio.com/unpleasant-facts-about-hangfire-632a3228ff8a – Lex Li Feb 19 '20 at 22:07

1 Answers1

2

It's not safe. Take a look at the guide here: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio

If the app shuts down unexpectedly (for example, the app's process fails), StopAsync might not be called. Therefore, any methods called or operations conducted in StopAsync might not occur.

It's not the case exactly, but it assumes that the application can be restarted. Same thing goes with application pool which restarts occasionally.

Overall, this will not assure that it will run daily. If the application restarts frequently for whatever reason, it could be that it never runs.

The same is true with libraries like hangfire.

Other solutions could be web jobs, or you could check if it has executed today by using some kind of persistence like a database that stores the last execution time and the IHostingService will check every some time and on startup whether or not it should execute the background job and act accordingly.

Athanasios Kataras
  • 25,191
  • 4
  • 32
  • 61
  • Well, I wouldn't entirely agree. See, the task runs immediatelly after the program (website) runs. It means that even if the website crush, the task will run once again when the app will restart (that usually happens automatically). Despite of the fact that this approach isn't best or cleanest from programmer's point of view it is still pretty good solution for quick and derty "must work now" solution. – undead10 Nov 24 '21 at 21:39