Click here to Skip to main content
15,884,629 members
Articles / Desktop Programming / System
Alternative
Tip/Trick

A Task Scheduler Library for .NET Applications

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
11 Jun 2014MIT1 min read 20.1K   343   14   4
This is an alternative for "A Task Scheduler Library for .NET Applications"

Introduction

This is a simple class which can be used for scheduling a task to run at a specific time everyday or to run a task every interval. This can be used for any scheduled tasks like cleaning up files or any other resources, synchronize data to your application from any external data providers, optimize database at regular intervals, send bulk emails or other notifications like SMS in less bandwidth used hours (probably during night time), etc.

Background

I'm using .NET framework >=4.0 class Task in the solution. So check your project is compatible with this utility. This is a trial to make an alternative for "A Task Scheduler Library for .NET Applications" having a cleaner design by spliting the Scheduler class into two classes as suggested by John Brett in this comment.

Using the Code

In this design, there is an abstract generic class ServiceBase. I preferred abstract class over interface for code reusability.

C#
// Used to schedule tasks to run on regular intervals or on specific time of everyday.
public abstract class SchedulerBase<T> : Timer, IDisposable
{
    // Returns a new instance of timer and starts it
    // param name="Time": Interval time to execute the timer
    // param name="Trigger": Action to call in a new Thread when timer elapses
    protected SchedulerBase(TimeSpan Time, Action Trigger)
    {
        this.Time = Time;
        Reset();
        Elapsed += (s, e) => Task.Factory.StartNew(Trigger);
    }

    // Returns a new instance of timer and starts it
    // param name="Time": Interval time to execute the timer
    // param name="Trigger": Function to call in a new Thread when timer elapses
    // param name="CallBackFn": Optional call back Action to execute after completing the Trigger function. 
    // Input parameter of this Action is the result of Trigger function
    protected SchedulerBase(TimeSpan Time, Func<T> Trigger, Action<T> CallBackFn)
    {
        this.Time = Time;
        Reset();
        Elapsed += (s, e) => Task.Factory.StartNew(Trigger)
            .ContinueWith(prevTask => CallBackFn(prevTask.Result));
    }

    protected TimeSpan Time { get; set; }

    // Resets and restarts the scheduler
    public void Reset()
    {
        Stop();
        Interval = GetInterval();
        Enabled = true;
        Start();
    }

    // A template method to return TimeSpan difference of the next schedule time with respect to current time
    protected abstract double GetInterval();

    // Stop and dispose the timer
    protected override void Dispose(bool disposing)
    {
        Stop();
        base.Dispose(disposing);
    }
}

IntervalScheduler is one of the concrete classes inheriting from the SchedulerBase class. This class provides the interval based scheduling behavior.

C#
// Scheduler which triggers at a specific time interval
public class IntervalScheduler<T> : SchedulerBase<T>
{
    public IntervalScheduler(TimeSpan Time, Action Trigger) : base(Time, Trigger) { }

    public IntervalScheduler(TimeSpan Time, Func<T> 
    Trigger, Action<T> CallBackFn) : base(Time, Trigger, CallBackFn) { }

    protected override double GetInterval()
    {
        return Time.TotalMilliseconds;
    }
}

TimeScheduler is the other class inherits from SchedulerBase and provides the behavior to run the scheduler at specific time of a day.

C#
// Scheduler which runs at a specific time everyday.
public class TimeScheduler<T> : SchedulerBase<T>
{
    public TimeScheduler(TimeSpan Time, Action Trigger) : base(Time, Trigger) { }

    public TimeScheduler(TimeSpan Time, Func<T> Trigger, 
    Action<T> CallBackFn) : base(Time, Trigger, CallBackFn) { }

    protected override double GetInterval()
    {
        // Scheduled time of today
        DateTime nextRunOn =
            DateTime.Today.AddHours(Time.Hours).AddMinutes(Time.Minutes).AddSeconds(Time.Seconds);
        if (nextRunOn < DateTime.Now)
        {
            nextRunOn = nextRunOn.AddMinutes(1);
        }
        if (nextRunOn < DateTime.Now) // If nextRunOn time is already past, set to next day
        {
            nextRunOn = nextRunOn.AddDays(1);
        }
        return (nextRunOn - DateTime.Now).TotalMilliseconds;
    }
}

You can create schedulers simply calling specific constructors.

C#
// A function that executes every 5 minutes
SchedulerBase<dynamic> FiveMinScheduler = 
new IntervalScheduler<dynamic>(TimeSpan.FromMinutes(5), FiveMinScheduledFn);

// A function that executes only once in a day at a specific time
SchedulerBase<dynamic> NightScheduler = 
new TimeScheduler<dynamic>(TimeSpan.FromHours(2), NightScheduledFn);

// Using parameters in a schedule function
SchedulerBase<dynamic> ParamerizedScheduler = 
new IntervalScheduler<dynamic>(TimeSpan.FromDays(7), () => ParamerizedScheduledFn(i, 6));

// Using result of scheduled function in another callback function
SchedulerBase<string> CallbackScheduler = 
new IntervalScheduler<string>(TimeSpan.FromSeconds(30), 
    () => ParamerizedScheduledFn(i, 6), CallBackFunc);

Some of the scheduled functions used above are:

C#
internal void NightScheduledFn()
{
    Helper.WriteLog("I run at 2AM everyday. Current time is: " + DateTime.Now);
}

internal string ParamerizedScheduledFn(int i, int j)
{
    Helper.WriteLog(String.Format("Got parameters i={0} 
    and j={1}. Current time is: {2}", i, j, DateTime.Now));
    return (i*j).ToString(CultureInfo.InvariantCulture);
}

internal void CallBackFunc(string result)
{
    Helper.WriteLog(String.Format("Scheduled task finished on: {0}. 
    Result of scheduled task is: {1}", DateTime.Now, result));
}

Points of Interest

By comparing the alternative implementation, we can see how splitting the Scheduler class into two classes can achieve a cleaner design.

See the alternative implementation using factory pattern.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer CCS Technologies
India India
I'm Sen Jacob. Find more info about me at StackOverflow Careers

Comments and Discussions

 
Questionnot installed successfully Pin
Ketan Mevada12-Jun-14 3:26
Ketan Mevada12-Jun-14 3:26 
AnswerRe: not installed successfully Pin
Sen Jacob12-Jun-14 6:02
professionalSen Jacob12-Jun-14 6:02 
GeneralRe: not installed successfully Pin
Ketan Mevada16-Jun-14 4:02
Ketan Mevada16-Jun-14 4:02 
GeneralThoughts Pin
PIEBALDconsult11-Jun-14 14:18
mvePIEBALDconsult11-Jun-14 14:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.