DotnetAsyncScheduler 1.0.0

dotnet add package DotnetAsyncScheduler --version 1.0.0
                    
NuGet\Install-Package DotnetAsyncScheduler -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DotnetAsyncScheduler" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DotnetAsyncScheduler" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="DotnetAsyncScheduler" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DotnetAsyncScheduler --version 1.0.0
                    
#r "nuget: DotnetAsyncScheduler, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=DotnetAsyncScheduler&version=1.0.0
                    
Install DotnetAsyncScheduler as a Cake Addin
#tool nuget:?package=DotnetAsyncScheduler&version=1.0.0
                    
Install DotnetAsyncScheduler as a Cake Tool

DotNetAsyncScheduler

Releases

Prerelease versions from Master

CI-Release Build status available in MyGet-Feed

Requirements / Dependencies

  • .NET Core 2.0 or .NET Framework 4.7.2

  • Microsoft.Extensions.DependencyInjection.Abstractions

  • Microsoft.Extensions.Logging.Abstractions

  • JetBrains.Annotations

Implementation Goals

  • Simple triggering of async Jobs based on Schedules
  • High integration with Dependency Injection for Jobs and Schedules via Microsoft.Extensions.DependencyInjection.Abstractions
  • Split from Jobs and Schedules
  • Allow implementing of restrictions (e.g. Mutex, Slow-Start)
  • Use async-await and CancellationToken
  • One job cannot run in parallel
  • Intelligent error handling (e.g. allow immediate restart in Scheduler)
  • Allow stopping / restarting and chaning of jobs/schedules on the fly
  • Use logging via Microsoft.Extensions.Logging.Abstractions

What we don't have:

  • Any kind of persistence of job runs or history (e.g. in Database)
  • No serialization (yeay) of jobs or job parameters
  • Jobs with parameters

Execution model

In each cycle (cycle delay can be configured), the Scheduler pulls all Schedules of jobs, which are currently not running. If a schedule returns a priority number greater than 0, the job is marked for execution. The marked jobs are then ordered by the priority number. One after the other, the jobs are started, when the job restrictions allow this.

Example

Scheduler

//setup your DI
var serviceProvider = new ServiceCollection()
    .RegisterAsyncScheduler()
    .BuildServiceProvider();

var scheduler = serviceProvider.GetService<Scheduler>();
if (scheduler == null)
{
    throw new NullReferenceException("Unable to get Scheduler");
}

var jobManager = scheduler.JobManager;

jobManager.AddJob<SimpleTask>(new TimeSlotSchedule
{
    StartTime = DateTime.UtcNow + TimeSpan.FromSeconds(20)
});
jobManager.AddJob<ExampleTask2>(new IntervalSchedule(TimeSpan.FromSeconds(25)));
jobManager.AddJob<DownloadTask>(new IntervalSchedule(TimeSpan.FromSeconds(10)));
jobManager.AddJob<EndlessLoopTask, ScheduleOnce>();
scheduler.AddRestriction(new ConcurrentJobRestriction
{
    MaximumParallelJobs = 10
});
scheduler.AddRestriction(new MutexRestriction(typeof(SimpleTask), typeof(DownloadTask)));

var schedulerTask = scheduler.Start(_cancellationTokenSource.Token);
await schedulerTask;

Hint: There is no stop method. Use the cancellationToken to stop the scheduling.

Job

public class DownloadTask : IJob
{
    private readonly ILogger<DownloadTask> _logger;

    public DownloadTask(ILogger<DownloadTask> logger)
    {
        _logger = logger;
    }

    public async Task<object> Start(CancellationToken cancellationToken)
    {
        var httpClient = new HttpClient();
        _logger.LogInformation("Starting download ...");
        await httpClient.GetAsync("https://www.google.com", cancellationToken);
        _logger.LogInformation("Download finished ...");
        return "Download success";
    }
}

IJob

A job should highly use async methods to avoid blocking other jobs. If the job's main action uses not-async CPU intensive work, consider to spawn a new task/thread via Task.Run inside your Job.

The job may end with an exception in case of errors. The return value is logged using ToString().

Schedules

Schedules define, when a Job is executed: If schedule returns int>0, the Job is started (when no restrictions apply). Jobs with higher numbers are started first, which is only relevant, when Restrictions (e.g. Mutex, MaxJobNumber) are applied. A Schedule might handle retry in case of failures.

As Schedules can be created via DI, they may connect to a database / config file to read current configuration state. In case of IO-Operations in Schedule consider increasing the LoopDelay.

Predefined Schedules

There are several examples of schedule implementation available:

  • ScheduleOnce: Schedule immediately, when not executed or failed
  • ScheduleOnceWithRetryDelay: Schedule immediately. Retry on failure with certain configurable delay
  • ScheduleEndless: Always re-schedule, when finished
  • IntervalSchedule: Schedule based on a TimeSpan interval
  • IntervalScheduleWithRetryDelay: Same as IntervalSchedule, but with retry for failed jobs
  • TimeSlotSchedule: Schedule based on a Datetime after which it should start

Restrictions

Restrictions can be used to prevent Jobs from being started based on the current context (other running jobs). They are executed shortly before a Job is started.

Feel free to implement your own restrictions.

Predefined Restrictions

  • ConcurrentJobRestriction: Restrict number of parallel jobs
  • MutexRestriction: Restrict certain jobs from running in parallel
  • SlowStartRestriction: Don't start all jobs at once (experimentell)

Disclaimer

Use at your own risk.

Alternatives

  • Hangfire
  • Quartz.NET
  • Fluentscheduler
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.1 is compatible.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Framework net472 is compatible.  net48 was computed.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.0 53,483 12/26/2020