如何复用ASP.NET Core后台服务同时执行每日与每月报表任务
复用后台服务同时执行每日和每月报表任务
完全可以复用现有的ReviewSummaryBackgroundService来同时处理每日午夜和每月初的报表任务,只需要扩展现有逻辑,添加月度任务的触发判断和延迟计算即可。以下是修改后的完整代码:
namespace API.Services { public class ReviewSummaryBackgroundService : BackgroundService { protected readonly 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; } private static TimeSpan TimeUntilNextMonthStart() { var nextMonth = DateTime.Today.AddMonths(1); var nextMonthStart = new DateTime(nextMonth.Year, nextMonth.Month, 1); return nextMonthStart - DateTime.Now; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { // 开发环境直接执行,生产环境等待到下一个最近的触发点(午夜或月初) var delay = _env.IsProduction() ? TimeSpan.FromMilliseconds(Math.Min(TimeUntilMidnight().TotalMilliseconds, TimeUntilNextMonthStart().TotalMilliseconds)) : TimeSpan.Zero; while (!stoppingToken.IsCancellationRequested) { await Task.Delay(delay, stoppingToken); try { await OnTimerFiredAsync(stoppingToken); } catch (Exception ex) { // 后续可添加日志记录逻辑 } // 每次执行后重新计算最短等待时间,确保每日运行,同时月初触发月度任务 delay = TimeSpan.FromMilliseconds(Math.Min(TimeUntilMidnight().TotalMilliseconds, TimeUntilNextMonthStart().TotalMilliseconds)); } } private async Task OnTimerFiredAsync(CancellationToken stoppingToken) { using (var scope = _scopeFactory.CreateScope()) { var reviewSummaryService = scope.ServiceProvider.GetRequiredService<IReviewSummaryService>(); // 执行每日报表任务 await reviewSummaryService.ExportDailyExcelReportAsync(); // 判断是否为当月第一天,执行月度报表任务 if (DateTime.Now.Day == 1) { await reviewSummaryService.ExportMonthlyExcelReportAsync(); } } } } }
关键改动说明
- 新增月度延迟计算方法:
TimeUntilNextMonthStart()用于计算当前时间到下一个自然月第一天0点的时间间隔 - 动态调整等待时间:每次任务执行后,取「到午夜的时间」和「到下月初的时间」中的较小值作为下一次延迟,保证服务每日运行一次,同时在月初当天午夜触发月度任务
- 任务触发判断:在
OnTimerFiredAsync中检查当前日期是否为当月第一天,满足条件则执行月度报表任务,确保每月仅运行一次 - 开发环境兼容:开发环境直接执行任务,无需等待,方便本地测试
内容的提问来源于stack exchange,提问作者Qiuzman
相关产品推荐
相关产品推荐

