在 .NET中使用Cronos实现计划任务功能

作者:微信公众号:【架构师老卢】
4-27 8:21
77

概述:Cronos 是 .NET 的任务计划库,允许使用 CRON 模式在特定时间或间隔计划和执行任务。在本文中,我将介绍如何在 .NET 8 应用程序的后台设置和使用任务计划。先决条件.NET 8.0Visual Studio 2022Nuget 包 CronosWeb API在API的Program.cs类中,配置如下图所示:using Sample.Scheduler.Core.Extensions;using Sample.Scheduler.Core.TimerSchedulers;var builder = WebApplication.CreateBuilder(args);build

Cronos 是 .NET 的任务计划库,允许使用 CRON 模式在特定时间或间隔计划和执行任务。

在本文中,我将介绍如何在 .NET 8 应用程序的后台设置和使用任务计划。

先决条件

  • .NET 8.0
  • Visual Studio 2022
  • Nuget 包 Cronos

Web API

在API的Program.cs类中,配置如下图所示:

using Sample.Scheduler.Core.Extensions;
using Sample.Scheduler.Core.TimerSchedulers;

var builder = WebApplication.CreateBuilder(args);
builder.AddSerilog();

builder.Services.AddRouting(options => options.LowercaseUrls = true);
builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddCronJob<TimerSendEmail>(c => c.CronExpression = @"0 */1 * * * *");
builder.Services.AddCronJob<TimerCheckDatabase>(c => c.CronExpression = @"* * * * * *");

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.MapControllers();

app.Run();

下一步是创建扩展类 CronJobExtensions,负责使用 CronExpression 控制每个任务的下一个计划:

public abstract class CronJobExtensions : BackgroundService
{
 private readonly CronExpression _expression;
 private readonly TimeZoneInfo _timeZoneInfo;
 private readonly IServiceProvider _serviceProvider;

 protected CronJobExtensions(string cronExpression, TimeZoneInfo timeZoneInfo, IServiceProvider serviceProvider)
 {
  _expression = CronExpression.Parse(cronExpression, CronFormat.IncludeSeconds);
  _timeZoneInfo = timeZoneInfo;
  _serviceProvider = serviceProvider;
 }

 protected override async Task ExecuteAsync(CancellationToken cancellationToken)
 {
  while (!cancellationToken.IsCancellationRequested)
  {
   var now = DateTimeOffset.Now;
   var next = _expression.GetNextOccurrence(now, _timeZoneInfo);
   if (!next.HasValue) continue;

   var delay = next.Value - now;
   await Task.Delay(delay, cancellationToken);

   if (cancellationToken.IsCancellationRequested) continue;

   try
   {
    using var scope = _serviceProvider.CreateScope();
    await DoWork(scope, cancellationToken);
   }
   catch (Exception ex)
   {
    Log.Error(ex, nameof(ExecuteAsync));
   }
  }
 }

 public abstract Task DoWork(IServiceScope scope, CancellationToken cancellationToken);
}

public interface IScheduleConfig<T>
{
 string CronExpression { get; set; }
 TimeZoneInfo TimeZoneInfo { get; set; }
}

public class ScheduleConfig<T> : IScheduleConfig<T>
{
 public string CronExpression { get; set; }
 public TimeZoneInfo TimeZoneInfo { get; set; } = TimeZoneInfo.Local;
}

接下来,必须创建负责注册计划的扩展类 ScheduledServiceExtensions:

public static class ScheduledServiceExtensions
{
 public static IServiceCollection AddCronJob<T>(this IServiceCollection services, Action<IScheduleConfig<T>> options) where T : CronJobExtensions
 {
  var config = new ScheduleConfig<T>();
  options.Invoke(config);

  services.AddSingleton<IScheduleConfig<T>>(config);

  services.AddHostedService<T>();

  return services;
 }
}

最后,让我们创建用于调度操作的类,在此示例中,我们将创建一个每秒触发一次的计划,每分钟触发一次。这两个时间表在Program.cs类中注册

public class TimerCheckDatabase : CronJobExtensions
{
 public TimerCheckDatabase(IScheduleConfig<TimerCheckDatabase> config, IServiceProvider serviceProvider)
  : base(config.CronExpression, config.TimeZoneInfo, serviceProvider)
 {
 }

 public override Task DoWork(IServiceScope scope, CancellationToken cancellationToken)
 {
  Serilog.Log.Information("Verified Database!");
  return Task.CompletedTask;
 }
}

public class TimerSendEmail : CronJobExtensions
{
 public TimerSendEmail(IScheduleConfig<TimerSendEmail> config, IServiceProvider serviceProvider)
  : base(config.CronExpression, config.TimeZoneInfo, serviceProvider)
 {
 }

 public override Task DoWork(IServiceScope scope, CancellationToken cancellationToken)
 {
  Serilog.Log.Information("Email sent!");
  return Task.CompletedTask;
 }
}

测试

要测试计划,请运行 API 并在应用程序控制台中分析 Serilog 生成的日志:

可以看出,检查数据库的任务计划每秒触发一次,而发送电子邮件的计划每分钟触发一次。

Cronos 是一个用于解析 Cron 表达式和计算下一次出现次数的库,有了它,可以安排重要的后台任务,例如:每天早上执行数据库维护、不时从源捕获数据、创建警报等。

相关留言评论
昵称:
邮箱:
阅读排行