Overview

Task Scheduler Engine adds cron-like or At-like scheduling to your .NET application. This 250-line (18KB compiled) library offers considerable functionality without bloat, and without any external dependencies. Schedules are configured with a simple fluent API, or XML configuration. Schedules are evaluated using bitwise arithmetic, making it extremely fast & light. Example uses could be for triggering refreshes on an RSS feed, fetching updated weather data, home automation, alarm clocks, and more.

Condider using this library any time you need 1-second granularity in your application, and when your scheduling can live entirely in-memory (i.e., not load balanced, and doesn't need a database or other concurrency control), and it matters when your tasks execute, not just how often (i.e., something should occur at 6am every Monday, not just every x days). If you need load balancing and concurrency control, consider Quartz.NET.

NuGet

This project is available via NuGet http://nuget.org/List/Packages/TaskSchedulerEngine

Donate

If you like this project and want to buy me a beer or a coffee to say thanks, feel free: https://gumroad.com/l/VkTp

Quick Start

  • Create a class that implements ITask. This is the class that will respond to a scheduled event.
    • Only one instance will be created per schedule. Initialize will be called once when the schedule is created; HandleConditionsMetEvent will be called each time the timer event occurs. Keep this in mind if you trigger long-running processes at short intervals; multiple threads can execute HandleConditionsMetEvent against a single instance simultaneously.
  • Set up a schedule, using either the fluent API or the XML configuration, instructing it to execute your ITask (you may set up multiple tasks to execute in the same schedule; keep calling Execute)
var s = new Schedule()
    .AtSeconds(0, 10, 20, 30, 40, 50)
    .WithLocalTime()
    .WithName("PrimaryKey")
    .Execute<ConsoleWriteTask>();
  • Call Start with your schedule(s):
SchedulerRuntime.Start(s); 
  • SchedulerRuntime supports Add, Update and Deletion of running schedules. The Name property is used as a primary key; just commit it to the runtime to activate. XML-configured schedules can also be named and thus can be modified at runtime as well.
var nowAtFives = new Schedule()
    .AtSeconds(5, 15, 25, 35, 45, 55)
    .WithLocalTime()
    .WithName("PrimaryKey")
    .Execute<ConsoleWriteTask>();
SchedulerRuntime.UpdateSchedule(nowAtFives);

XML Configuration

Task Scheduler Engine also supports XML configuration. You lose the type-safety and Intellisense of the fluent API, but you gain deployment flexibility. Again, name your task if you want to be able to modify it at runtime. Here's the same schedule defined in XML:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="taskSchedulerEngine"
             type="TaskSchedulerEngine.Configuration.TaskSchedulerEngineConfigurationSection, 
TaskSchedulerEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </configSections>
  <taskSchedulerEngine>
    <schedule>
      <at month="*" dayOfMonth="*" dayOfWeek="*" hour="*" minute="*" second="0,10,20,30,40,50" kind="Local" name="primaryKey">
        <execute>
          <task type="TaskSchedulerEngine.ConsoleWriteTask, TaskSchedulerEngine, 
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
                parameters="" />
        </execute>
      </at>
    </schedule>
  </taskSchedulerEngine>
</configuration>

Then call
SchedulerRuntime.StartWithConfig("taskSchedulerEngine"); 

Examples

  • Execute a task every second
var s = new Schedule().WithUtc();
<at name="scheduleName" month="*" dayOfMonth="*" dayOfWeek="*" hour="*" minute="*" second="*" kind="Utc" /> 
  • Execute a task every five seconds
var s = new Schedule().AtSeconds(0,5,10,15,20,25,30,35,40,45,50,55).WithUtc();
<at name="scheduleName" month="*" dayOfMonth="*" dayOfWeek="*" hour="*" minute="*" 
   second="0,5,10,15,20,25,30,35,40,45,50,55" kind="Utc" /> 
  • Execute a task every minute
    • This more explicitly reads, execute a task on the 0th second of every minute.
var s = new Schedule().AtSeconds(0).WithUtc();
<at name="scheduleName" month="*" dayOfMonth="*" dayOfWeek="*" hour="*" minute="*" second="0" kind="Utc" /> 
  • Execute a task at 3:00:00am and 3:00:00pm every Sunday
var s = new Schedule().AtDaysOfWeek(0).AtHours(3,15).AtMinutes(0).AtSeconds(0).WithUtc();
<at name="scheduleName" month="*" dayOfMonth="*" dayOfWeek="0" hour="3,15" minute="0" second="0" kind="Utc" /> 
  • Never execute this task
    • Probably not something you would intend to do; but—it is legal syntax. Execute this task at 3am on the 31st of February.
var s = new Schedule().AtMonths(2).AtDaysOfMonth(31).AtHours(3).AtSeconds(0).WithUtc();
<at month="2" dayOfMonth="31" dayOfWeek="*" hour="3" minute="0" second="0" kind="Utc" /> 

Threading

The TaskEvaluationPump runs on its own thread. Start and Stop it via the SchedulerRuntime.
In ScheduleDefinition, a ConditionsMet event is raised on its own thread via the OnConditionsMetAsync method (as called by the Evaluate method). Each of the ITasks that are connected to the ConditionsMet event will be executed in series on the worker thread.
In other words, when the current time matches the scheduled time, a new thread will be created to execute all of the attached ITasks, one after the other.
For a given ScheduleDefinition, each associated ITask will have one instance.

If you like this project

Or have suggestions/comments, please leave a message in the discussions. I'd love to hear from users.

Last edited Feb 21, 2012 at 4:21 AM by pettijohn, version 23