I'm Keyvan Nayyeri, a 25 years old Ph.D. student at
the Computer Science department of
the University of Texas at San Antonio.
I'm also
a Software Architect and Developer and previously held a B.Sc.
degree in Applied Mathematics.
This is my blog where I publish content about various topics specifically Programming Languages and Compilers, Software
Engineering and Programming.
Running scheduled tasks in an application is a common scenario for any platform and any type of application. For .NET and especially for Windows applications this is a straightforward task. Thank to the infrastructure of Windows programming you don’t have any problem to get this done.
But how about web-based scenarios? When it comes to the online server-side applications you need to deal with a harder process because there isn’t a good infrastructure for this purpose. This is due to the life-cycle of an ASP.NET application as well as built-in classes provided by ASP.NET.
There are some common solutions to run schedules tasks in an ASP.NET application but I think that none of them are very well documented. One solution is using SQL Server jobs that are not possible everywhere and also have some issues. There are also some other methods but the most common one is what I want to cover in this post series.
Back to the days when I was very active on Community Server forums there were many questions and requests from technical users asking about a way to apply the Community Server Jobs system in their applications. That system is now renamed to Community Server Tasks but the core mechanism is the same.
After seeing the necessity of having a good resource about this topic I decided to stick with it and write a new post series that covers the task scheduling topic in a simple way to let a wider range of developers use such mechanism in their applications. So here is the first part of the series!
To build a task scheduler system you need to use a built-in Timer object that elapses on a regular basis. Nothing especial with this idea because most likely you could guess this! But the point is how and when to start and stop this Timer and also how to manage its workflow? The answer will be answered in enough details here!
The solution consists of some steps in general:
In this part I talk about the first step and in the second part will cover the TaskScheduler class. Here my goal is to cover the process but you can simply grab this implementation and extend it to build a general task scheduling system for yourself. I have mine and am sure that it’s worthwhile to build your own for your projects!
The Task class is a class that represents your scheduled task with some properties and methods related to the scheduling process as well as some specific properties and methods related to the business logic of the task.
Here I write a Task class that covers the main concepts related to scheduler as well as implementing a simple scenario that logs the current time into a text file on a regular basis.
Step by step I describe the properties and methods of this class to let you know how it works.
Fields and Properties
First of all, you need to define some fields and properties for your task. The main field of the class is a System.Timers.Timer object that plays an important role in the scheduling mechanism.
Beside this field, there are also some properties. Most of them are general properties related to scheduler system. Here is a short description about these properties:
So at the first step the Task class would look like this:
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Timers;
using System.Threading;
using System.IO;
namespace TaskSchedulerSample
{
public class Task
{
#region Fields
System.Timers.Timer timer = null;
#endregion
#region Properties
public string Name { get; set; }
public bool IsRunning { get; set; }
public DateTime LastRunTime { get; set; }
public bool IsLastRunSuccessful { get; set; }
public double Interval { get; set; }
public bool Stopped { get; set; }
public string FilePath { get; set; }
#endregion
}
}
Constructors
This class has a single public constructor. This constructor gets a double parameter as the interval value of the timer control in order to initially set the Interval property of the class and then calls the Initialize method in order to initialize the task. So nothing special to mention about this constructor.
#region Public Constructors
public Task(double interval)
{
this.Interval = interval;
Initialize();
}
#endregion
Public Methods
As you may guess, the Task class should provide some operations for the scheduler to let it start and stop the task. So you need to define two public methods called Start and Stop that manage these operations.
The Start method sets the Stopped property to false and calls the StartTask method which manages the rest of the process to start the task. And Stop method simply sets the Stopped property to true. Later you’ll see how this property plays its role in the process.
#region Public Methods
public void Start()
{
this.Stopped = false;
this.StartTask();
}
public void Stop()
{
this.Stopped = true;
}
#endregion
Private Methods
But most of the business logic is implemented in the private methods.
The first private method is Initialize that was used to initialize the task and especially its Timer object. This method sets the Stopped property to false and creates and instance of the Timer object with the specified internal then sets an event handler for the Elapsed event.
private void Initialize()
{
this.Stopped = false;
timer = new System.Timers.Timer(this.Interval);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Enabled = true;
}
The second method is StartTask that was used to start the scheduling process of the task. First of all this method checks the Stopped property and doesn’t follow if it is set to true otherwise it creates a new thread to run the task on its own thread.
private void StartTask()
{
if (!this.Stopped)
{
Thread thread = new Thread(new ThreadStart(Execute));
thread.Start();
}
}
The Execute method is where the main work is done. I don’t think that it is necessary to describe anything about this method because the simple code is self-explanatory so just take a look at the code.
private void Execute()
{
try
{
this.IsRunning = true;
this.LastRunTime = DateTime.Now;
File.AppendAllText(this.FilePath, DateTime.UtcNow.ToString() + "\n");
this.IsLastRunSuccessful = true;
}
catch
{
this.IsLastRunSuccessful = false;
// Handle the exception
}
finally
{
this.IsRunning = false;
}
}
And the last method is the event handler for the Elapsed event of the timer object. It simply checks if the task is currently running and then calls the StartTask method to run the task on a regular basis.
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (!this.IsRunning)
StartTask();
}
So the final code for the Task class is this:
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Timers;
using System.Threading;
using System.IO;
namespace TaskSchedulerSample
{
public class Task
{
#region Fields
System.Timers.Timer timer = null;
#endregion
#region Properties
public string Name { get; set; }
public bool IsRunning { get; set; }
public DateTime LastRunTime { get; set; }
public bool IsLastRunSuccessful { get; set; }
public double Interval { get; set; }
public bool Stopped { get; set; }
public string FilePath { get; set; }
#endregion
#region Public Constructors
public Task(double interval)
{
this.Interval = interval;
Initialize();
}
#endregion
#region Public Methods
public void Start()
{
this.Stopped = false;
this.StartTask();
}
public void Stop()
{
this.Stopped = true;
}
#endregion
#region Private Methods
private void Initialize()
{
this.Stopped = false;
timer = new System.Timers.Timer(this.Interval);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Enabled = true;
}
private void StartTask()
{
if (!this.Stopped)
{
Thread thread = new Thread(new ThreadStart(Execute));
thread.Start();
}
}
private void Execute()
{
try
{
this.IsRunning = true;
this.LastRunTime = DateTime.Now;
File.AppendAllText(this.FilePath, DateTime.UtcNow.ToString() + "\n");
this.IsLastRunSuccessful = true;
}
catch
{
this.IsLastRunSuccessful = false;
// Handle the exception
}
finally
{
this.IsRunning = false;
}
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (!this.IsRunning)
StartTask();
}
#endregion
}
}
Alright, the next part describes how to apply this Task class in the scheduler system to run the task.
Reflective Perspective - Chris Alcock » The Morning Brew #119
Jun 20, 2008 1:53 AM
#
Pingback from Reflective Perspective - Chris Alcock » The Morning Brew #119
Dew Droplet - June 20, 2008 | Alvin Ashcraft's Morning Dew
Jun 20, 2008 11:00 AM
#
Pingback from Dew Droplet - June 20, 2008 | Alvin Ashcraft's Morning Dew
Dave Burke
Jun 20, 2008 6:07 PM
#
I was thinking a lot this past week since moving to BE.NET how much use I could get out of a task scheduler system, exactly what you're laying out here. Thank you, K-man! Are you taking it all the way to kicking-off the task, like in the cs.config <tasks /> area? Please say yes. hehe.
Seriously, this is fantastic. Man, I sure am enjoying these down times of yours when you're not producing much! :-)
Keyvan Nayyeri
Jun 20, 2008 8:30 PM
#
@Dave,
Thank you, man :-) Actually I'm not going to talk about it in that level but I've developed a general framework like that for myself that is ready to go. If you need the source code, just ping me and I'll be more than happy to share it with you ;-)
Dave Burke
Jun 21, 2008 2:53 PM
#
That's very generous of you. I might have to get back to you on that. In the meantime, I'll be looking forward to Part 2!
How to Build a Task Scheduler System for the ASP.NET – Part 2
Jun 26, 2008 5:57 AM
#
In the first part of this short post series about building a task scheduler system for the ASP.NET I
Abidar – ASP.NET Task Scheduling Framework
Jun 30, 2008 12:08 PM
#
Recently I published a couple of blog posts about building a simple ASP.NET task scheduling system in
My Best Blog Posts in 2008
Dec 31, 2008 1:40 PM
#
In the past 3.5 years of blogging, I haven’t had such best pick up collections in the end of the year, but now that everybody is writing one, why shouldn’t I write my own?! Collecting this list, I could realize some interesting facts that completely changed
Steve
Mar 24, 2009 11:55 AM
#
You have any examples like this for an automated download of a zip file every 24hrs, then extracting it (images to images folder and .txt files to database)?
pedro
Sep 22, 2009 6:12 AM
#
Is it possible to send to me the source code of your framework?
thanks in advance
Keyvan Nayyeri
Sep 22, 2009 6:31 AM
#
Who's Dave? Are you talking to me?
Mark
Oct 26, 2009 3:02 PM
#
Could you send me the source code please? I'm looking for a framework to call by web app into action.
Keyvan Nayyeri
Oct 27, 2009 12:30 AM
#
@Mark
You better try the Abidar framework that is the enhanced version of this code:
http://nayyeri.net/abidar-1-0-beta-1
saber fatholahi
Nov 11, 2009 2:30 PM
#
to mayay eftekhari bo kourd,beray khoshavistem
har sar kavto bit,kayvan gian
adrian
Feb 28, 2010 11:34 PM
#
Leave a Comment