CronScheduler.AspNetCore

repository·master·Indexed 41 days ago

https://github.com/kdcllc/cronscheduler.aspnetcore

A lightweight scheduling library for .NET Core applications that allows developers to run tasks using cron syntax within IHost or IWebHost environments. It provides a simplified alternative to complex schedulers, featuring the IScheduledJob interface for task logic, IStartupJob for asynchronous initialization, and support for dynamic job registration at runtime via AddOrUpdate.

Tokens
5.6K
Snippets
21
Records
23
Agent score
51%

What's inside CronScheduler.AspNetCore

  1. Build and run the CronSchedulerWorker application

    master

    You can run the worker application using Docker or the .NET CLI.

    Using Docker

    1. Build the Docker Image:
    docker build --pull --rm -f "src/CronSchedulerWorker/Dockerfile" -t cronschedulerworker:latest .
    1. Run the Docker Container:
    docker run --rm -d cronschedulerworker:latest

    Using dotnet CLI

    1. Navigate to the project directory:
    cd src/CronSchedulerWorker
    1. Build and Run:
    dotnet build
    dotnet run
    # Build the Docker Image
    docker build --pull --rm -f "src/CronSchedulerWorker/Dockerfile" -t cronschedulerworker:latest .
    
    # Run the Docker Container
    docker run --rm -d cronschedulerworker:latest
  2. Install CronScheduler.AspNetCore

    master

    Depending on your hosting model, install the appropriate NuGet package via the .NET CLI:

    • For ASP.NET Core applications: dotnet add package CronScheduler.AspNetCore

    • For Generic Host (IHost) applications: dotnet add package CronScheduler.Extensions

    dotnet add package CronScheduler.AspNetCore
  3. Register jobs with the Scheduler

    master

    There are two primary ways to register jobs and their options within the Scheduler:

    1. Basic Registration (via IConfiguration)

    This is the most effective method when the job name and the configuration options name are identical. It uses the AddJob<TJob>() extension method.

    2. Complex Factory Registration

    Use this method when you need to register the same job type multiple times with different options or custom instantiation logic. This uses the AddJob(factory, options, jobName) overload.

    // 1. Basic registration
    services.AddScheduler(ctx =>
    {
        ctx.AddJob<TestJob>();
    });
    
    // 2. Complex factory registration
    services.AddScheduler(ctx =>
    {
        var jobName1 = "TestJob1";
    
        ctx.AddJob(
            sp =>
            {
                var options = sp.GetRequiredService<IOptionsMonitor<SchedulerOptions>>().Get(jobName1);
                return new TestJobDup(options, mockLoggerTestJob.Object);
            },
            options =>
            {
                options.CronSchedule = "*/5 * * * * *";
                options.RunImmediately = true;
            },
            jobName: jobName1);
    });
  4. Run the CronSchedulerApp using Docker

    master

    To run the demonstration application using Docker, follow these steps:

    1. Build the Docker Image:

      docker build --pull --rm -f "src/CronSchedulerApp/Dockerfile" -t cronscheduler:latest .
    2. Run the Docker Container:

      docker run --rm -d -p 4443:443/tcp -p 8080:80/tcp cronscheduler:latest
    docker build --pull --rm -f "src/CronSchedulerApp/Dockerfile" -t cronscheduler:latest .
    docker run --rm -d -p 4443:443/tcp -p 8080:80/tcp cronscheduler:latest
  5. Migrate from 2.x to 3.x

    master

    When migrating from version 2.x to 3.x, the primary change is the removal of the ScheduledJob base class in favor of the IScheduledJob interface.

    Key Changes:

    • Replace ScheduledJob with IScheduledJob: Your job classes should now implement the IScheduledJob interface instead of inheriting from a base class.
    • Implement Name property: Every job must implement a string Name { get; } property. For correct integration with SchedulerOptions, the job's Name must match the name used in your configuration/options.
    • Remove Schedule Properties from Job: The properties CronSchedule, CronTimeZone, and RunImmediately have been removed from the job implementation itself. These are now configured during job registration or via configuration.
    • Update ExecuteAsync: The ExecuteAsync method is no longer an override; it is a standard implementation of the interface method.
    // 3.x implementation pattern
    public class TorahQuoteJob : IScheduledJob
    {
        private readonly TorahQuoteJobOptions _options;
        // ... other dependencies
    
        public TorahQuoteJob(IOptionsMonitor<TorahQuoteJobOptions> options, ...)
        {
            // Use the Name property to retrieve the correct named options
            _options = options.Get(Name);
        }
    
        // job name and options name must match.
        public string Name { get; } = nameof(TorahQuoteJob);
    
        public async Task ExecuteAsync(CancellationToken cancellationToken)
        {
            // Job logic here
        }
    }
  6. Configure Background Queues

    master

    If your application requires queuing tasks for execution by a background service, follow these steps:

    1. Register the background service: services.AddBackgroundQueuedService();.
    2. Inject IBackgroundTaskQueue into your services.
    3. Use _taskQueue.QueueBackgroundWorkItem(async (token) => { ... }); to enqueue work.
    // Registration
    services.AddBackgroundQueuedService();
    
    // Usage
    public class MyService
    {
        private readonly IBackgroundTaskQueue _taskQueue;
    
        public MyService(IBackgroundTaskQueue taskQueue)
        {
            _taskQueue = taskQueue;
        }
    
        public void RunTask()
        {
            _taskQueue.QueueBackgroundWorkItem(async (token) => 
            {
                await Task.Delay(TimeSpan.FromSeconds(10), token);
            });
        }
    }
  7. Register scheduled jobs in .NET Core

    master

    To register jobs and their options, use the AddScheduler method during service configuration. You can also register a custom unobserved task exception handler to manage internal errors within the scheduler.

    services.AddScheduler(builder =>
    {
        builder.AddJob<MyScheduledJob, MyScheduledJobOptions>();
    });
    
    // Add a custom error processing for internal errors using an unobserved task exception handler
    builder.AddUnobservedTaskExceptionHandler(sp =>
    {
        var logger = sp.GetRequiredService<ILoggerFactory>().CreateLogger("CronJobs");
        return (sender, args) =>
        {
            logger?.LogError(args.Exception?.Message);
            args.SetObserved();
        };
    });
  8. Use IStartupJob for async initialization

    master

    Use IStartupJob to run asynchronous initialization processes (like database seeding or migrations) before the application host starts.

    1. Register the job using builder.Services.AddStartupJob<TStartupJob>().
    2. In your application startup sequence, call await app.RunStartupJobsAsync(); before await app.RunAsync();.
    var builder = WebApplication.CreateBuilder(args);
    
    // Register startup jobs
    builder.Services.AddStartupJob<SeedDatabaseStartupJob>();
    
    var app = builder.Build();
    
    // Execute startup jobs before running the app
    await app.RunStartupJobsAsync();
    await app.RunAsync();
  9. Register jobs in 3.x

    master

    In version 3.x, there are two primary ways to register jobs within the scheduler context:

    1. Basic Registration (via IConfiguration)

    This is the most effective method. It assumes that the name of the job and the name of the options in your configuration are identical.

    2. Complex Factory Registration

    Use this method when you need to register the same job type multiple times with different configurations or different names.

    Note: When using factory registration, you must manually resolve the named options using IOptionsMonitor<SchedulerOptions>.Get(jobName) within the factory delegate.

    // Basic registration
    services.AddScheduler(ctx =>
    {
        ctx.AddJob<TestJob>();
    });
    
    // Complex factory registration with different options/names
    services.AddScheduler(ctx =>
    {
        var jobName1 = "TestJob1";
    
        ctx.AddJob(
            sp =>
            {
                var options = sp.GetRequiredService<IOptionsMonitor<SchedulerOptions>>().Get(jobName1);
                return new TestJobDup(options, mockLoggerTestJob.Object);
            },
            options =>
            {
                options.CronSchedule = "*/5 * * * * *";
                options.RunImmediately = true;
            },
            jobName: jobName1);
    });
  10. Register scheduled jobs in ASP.NET Core

    master

    Register your jobs and their corresponding options within the dependency injection container using AddScheduler. You can also attach an unobserved task exception handler to manage internal errors within the scheduler.

    services.AddScheduler(builder =>
    {
        builder.AddJob<MyScheduledJob, MyScheduledJobOptions>();
    });
    
    // Add a custom error processing for internal errors using an unobserved task exception handler
    builder.AddUnobservedTaskExceptionHandler(sp =>
    {
        var logger = sp.GetRequiredService<ILoggerFactory>().CreateLogger("CronJobs");
        return (sender, args) =>
        {
            logger?.LogError(args.Exception?.Message);
            args.SetObserved();
        };
    });
  11. Configure job schedules in appsettings.json

    master

    Jobs can be configured via appsettings.json using a SchedulerJobs section. Common keys include:

    • RunImmediately: Boolean to trigger the job immediately upon startup.
    • CronSchedule: A Crontab format string defining the execution frequency.
    • Custom keys: Any properties defined in your SchedulerOptions subclass.

    Example configuration:

    {
      "SchedulerJobs": {
        "TorahQuoteJob": {
          "RunImmediately": true,
          "ApiUrl": "http://labs.bible.org/api/",
          "WebsiteUrl": "https://studybible.info/KJV_Strongs",
          "CronSchedule": "0/10 * * * * *",
          "Verses": [
            "Genesis 1:1-3",
            "Exodus 3:14-15"
          ]
        },
        "UserJob": {
          "RunImmediately": true,
          "CronSchedule": "2 9 * * *",
          "ClaimName": "TestClaim"
        }
      }
    }