Search code examples
c#asp.net-corebackground-service

How to schedule a background service to initiate every deployment without a controller action in IIS


I have built out a service to create an erxcel report which uploads to a cloud storage provider. I am creating a scheduled task to occur at midnight every night to run this service. My issue is I often am redeploying my application for updates and all and I am trying to figure out how to get this background task to run every time I redeploy. Can this be done automatically or do I need to create a controller action and manually remember to call it so the task starts?

My code is as follows:

public class ReviewSummaryBackgroundService : BackgroundService
{
    protected IReviewSummaryService _reviewSummaryService;
    
    public ReviewSummaryBackgroundService(IReviewSummaryService reviewSummaryService)
    {
        _reviewSummaryService = reviewSummaryService;
    }
    
    private static int SecondsUntilMidnight()
    {
        return (int)(DateTime.Today.AddDays(1.0) - DateTime.Now).TotalSeconds;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var countdown = SecondsUntilMidnight();

        while (!stoppingToken.IsCancellationRequested)
        {
            if (countdown-- <= 0)
            {
                try
                {
                    await OnTimerFiredAsync(stoppingToken);
                }
                catch(Exception ex)
                {
                    // in future log exception
                }
                finally
                {
                    countdown = SecondsUntilMidnight();
                }
            }
            await Task.Delay(1000, stoppingToken);
        }
    }

    private async Task OnTimerFiredAsync(CancellationToken stoppingToken)
    {
        await _reviewSummaryService.ExportExcelReportAsync();
    }
}

Solution

  • Assuming you're registering the background service as follows, it will be started when your application starts:

    builder.Services.AddHostedService<ReviewSummaryBackgroundService>();
    

    If you want to ensure that the report doesn't get created on each local debugging attempt, but when deployed to your prod environment, you could take advantage of the ASPNETCORE_ENVIRONMENT

    public ReviewSummaryBackgroundService(IWebHostEnvironment env, IReviewSummaryService reviewSummaryService) 
    {
        _Env = env;
        //...
    }
    
    private static TimeSpan TimeUntilMidnight()
    {
        return DateTime.Today.AddDays(1) - DateTime.Now;
    }
    
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var delay = _Env.IsProduction() ? TimeSpan.Zero : TimeUntilMidnight();
        
        while (!stoppingToken.IsCancellationRequested)
        {
            await Task.Delay(delay, stoppingToken);
            
            try
            {
                await OnTimerFiredAsync(stoppingToken);
            }
            catch (Exception ex)
            {
                // in future log exception
            }
    
            delay = TimeUntilMidnight();
        }
    }