运行多个 ASP.NET Core 后台服务

问题描述 投票:0回答:1

我有一些代码每天晚上午夜执行报告。我还有另一份报告需要在每个月初执行。是否可以共享此后台服务以同时运行?到目前为止我的代码是:

namespace API.Services
{
    public class ReviewSummaryBackgroundService : BackgroundService
    {
        protected IWebHostEnvironment _env;
        private readonly IServiceScopeFactory _scopeFactory;
 
        public ReviewSummaryBackgroundService(IWebHostEnvironment env, IServiceScopeFactory scopeFactory)
        {
             _env = env;
            _scopeFactory = scopeFactory;
        }
        
        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();
            }
        }

        private async Task OnTimerFiredAsync(CancellationToken stoppingToken)
        {
            // Create a scope using the CreateScope method
            using (var scope = _scopeFactory.CreateScope())
            {
                var reviewSummaryService = scope.ServiceProvider.GetRequiredService<IReviewSummaryService>();
                await reviewSummaryService.ExportDailyExcelReportAsync();
            }
        }
    }

}

另一个报告共享一个服务层,所以我只需调用:

reviewSummaryService.ExportMonthlyExcelReportAsync()
c# asp.net-core automation
1个回答
0
投票

如果您不想使用第三个产品/库,您可以使用下面的示例代码来实现此功能。

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore;

namespace API.Services
{
    public class ReviewSummaryBackgroundService : BackgroundService
    {
        private readonly IServiceScopeFactory _scopeFactory;
        private readonly ILogger<ReviewSummaryBackgroundService> _logger;
        private Timer _dailyTimer;
        private Timer _monthlyTimer;

        public ReviewSummaryBackgroundService(IServiceScopeFactory scopeFactory, ILogger<ReviewSummaryBackgroundService> logger)
        {
            _scopeFactory = scopeFactory;
            _logger = logger;
        }

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            // Set up the daily timer
            var dailyDelay = TimeUntilMidnight();
            _dailyTimer = new Timer(ExecuteDailyTask, null, dailyDelay, TimeSpan.FromDays(1));

            // Set up the monthly timer
            var monthlyDelay = TimeUntilNextMonth();
            _monthlyTimer = new Timer(ExecuteMonthlyTask, null, monthlyDelay, TimeSpan.FromDays(30));

            return Task.CompletedTask;
        }

        private TimeSpan TimeUntilMidnight()
        {
            return DateTime.Today.AddDays(1) - DateTime.Now;
        }

        private TimeSpan TimeUntilNextMonth()
        {
            var now = DateTime.Now;
            var firstDayNextMonth = new DateTime(now.Year, now.Month, 1).AddMonths(1);
            return firstDayNextMonth - now;
        }

        private async void ExecuteDailyTask(object state)
        {
            using (var scope = _scopeFactory.CreateScope())
            {
                var reviewSummaryService = scope.ServiceProvider.GetRequiredService<IReviewSummaryService>();
                try
                {
                    await reviewSummaryService.ExportDailyExcelReportAsync();
                    _logger.LogInformation("Daily report successfully executed at {Time}", DateTime.Now);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error executing daily report at {Time}", DateTime.Now);
                }
            }
        }

        private async void ExecuteMonthlyTask(object state)
        {
            using (var scope = _scopeFactory.CreateScope())
            {
                var dbContext = scope.ServiceProvider.GetRequiredService<YourDbContext>();
                var reviewSummaryService = scope.ServiceProvider.GetRequiredService<IReviewSummaryService>();

                try
                {
                    // get last run date from database
                    var lastRunDate = await dbContext.ReportStatuses
                        .Where(r => r.ReportName == "MonthlyReport")
                        .Select(r => r.LastRunDate)
                        .FirstOrDefaultAsync();

                    // if not found then can run once
                    if (lastRunDate == null || lastRunDate.Value.Month < DateTime.Now.Month || lastRunDate.Value.Year < DateTime.Now.Year)
                    {
                        await reviewSummaryService.ExportMonthlyExcelReportAsync();
                        _logger.LogInformation("Monthly report successfully executed at {Time}", DateTime.Now);

                        // update last run date
                        var reportStatus = await dbContext.ReportStatuses
                            .FirstOrDefaultAsync(r => r.ReportName == "MonthlyReport");

                        if (reportStatus != null)
                        {
                            reportStatus.LastRunDate = DateTime.Now;
                        }
                        else
                        {
                            // if no record then create it
                            reportStatus = new ReportStatus
                            {
                                ReportName = "MonthlyReport",
                                LastRunDate = DateTime.Now
                            };
                            await dbContext.ReportStatuses.AddAsync(reportStatus);
                        }

                        await dbContext.SaveChangesAsync();
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error executing monthly report at {Time}", DateTime.Now);
                }
            }
        }

        public override void Dispose()
        {
            _dailyTimer?.Dispose();
            _monthlyTimer?.Dispose();
            base.Dispose();
        }
    }

    // ReportStatus
    public class ReportStatus
    {
        public int Id { get; set; }
        public string ReportName { get; set; }
        public DateTime? LastRunDate { get; set; }
    }

    public class YourDbContext : DbContext
    {
        public DbSet<ReportStatus> ReportStatuses { get; set; }

    }
}
© www.soinside.com 2019 - 2024. All rights reserved.