Поиск  
Always will be ready notify the world about expectations as easy as possible: job change page
Aug 26

Scheduling tasks with Cronos in .NET

Scheduling tasks with Cronos in .NET
Автор:
Источник:
Просмотров:
1167

Mastering Scheduled Tasks in .NET with Cronos

Cronos is a task scheduling library for .NET that allows scheduling and executing tasks at specific times or intervals using the CRON pattern.

In this article, I will present how to set up and use task scheduling in the background in a .NET 8 application.

Prerequisites

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

Web API

In the Program.cs class of the API, configure as shown below:

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();

The next step is to create the extension class CronJobExtensions, responsible for controlling the next scheduling of each task using the 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;
}

Next, it is necessary to create the extension class ScheduledServiceExtensions responsible for registering the schedules:

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;
    }
}

And finally, let’s create the class for scheduling the actions, in this example, we will create a schedule to be triggered every second and another to be triggered every minute. These two schedules are registered in the Program.cs class

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;
    }
}

Testing

To test the schedules, run the API and analyze the logs generated by Serilog in the application console:

Serilog in the application console

It’s possible to see that the task scheduling that checks the database is triggered every second, while the scheduling that sends emails is triggered every minute.

Conclusion

Cronos is a library for parsing Cron expressions and calculating the next occurrences, with it, it is possible to schedule important background tasks, examples: Perform database maintenance every morning, capture data from a source from time to time, creation of alerts, etc.

Похожее
Oct 10
Author: Fiodar Sazanavets
.NET Aspire is an orchestration technology introduced in November 2022 alongside the .NET 8 release. And since it was released, it took the .NET community by storm. This technology allows developers to easily build and debug distributed applications locally, which...
Jul 22
Author: Ankit Sahu
Introduction In this article, we are going to discuss What Entity Framework is and How we can implement it in the .Net 8 project. This is a continuation of part 1, so if you are new to this article, please...
Jul 29
Author: C# Programming Obinna “Anderson” Asiegbulam
Introduction Open Data Protocol (OData) is a standard protocol for building and consuming RESTful APIs. It extends traditional REST-based data access techniques by providing a uniform way to expose, structure, and manipulate data. Originally developed by Microsoft, OData is widely...
Nov 29, 2023
Author: Rico Fritzsche
Streamline Your .NET 8 Projects with the Power of MediatR and Blazor In this article, I want to revisit how the Vertical Slice Architecture can be used. This article takes an in-depth look at feature slicing and its application to...
Написать сообщение
Тип
Почта
Имя
*Сообщение