我有一些代码每天晚上午夜执行报告。我还有另一份报告需要在每个月初执行。是否可以共享此后台服务以同时运行?到目前为止我的代码是:
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()
如果您不想使用第三个产品/库,您可以使用下面的示例代码来实现此功能。
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; }
}
}