You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何复用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 02:37:20