Поиск  
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
Автор:
Источник:
Просмотров:
1052

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.

Похожее
Jul 18
Author: Ankit Sahu
Introduction Creating a CRUD (Create, Read, Update, Delete) API in .NET 8 with an In-memory collection is a common scenario in web development. In this article, we’ll walk through building a complete .NET 8 Web API with a real-world use...
Aug 19
Author: Umair Rasheed
Introduction Building real-time applications has become essential in modern web development, especially for features like notifications, chat systems, and live updates. SignalR, a powerful library for ASP.NET, enables seamless real-time communication between server-side code and client-side web applications. In this...
Apr 15
Author: Olorundara Komolafe
Scheduling one or more background tasks is almost inevitable when building robust, self-sustaining APIs with .NET. A few packages have been around for years, such as Hangfire and Quartz.NET. ASP.NET Core allows background tasks to be implemented as hosted services....
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...
Написать сообщение
Тип
Почта
Имя
*Сообщение