Update: Scheduled Tasks in ASP.NET!

So as I promised I did write my sample project for using this. I’ll include the full files later as the majority of it is just wrappers around classes the files that really do all the magic is the code behind for the default.aspx and the TaskManager.cs file.

public partial class _Default : Page
{
private readonly TaskManager taskManager = new TaskManager();

protected void Page_Load(object sender, EventArgs e)
{
var printTask = taskManager.TaskList.Find(t => t.Id.GetValueOrDefault() == 1);

lblStatus.Text = printTask != null ? (printTask.Active ? "Active" : "InActive") : "Task not found";
}

protected void btnStartTasks_Click(object sender, EventArgs e)
{
taskManager.TaskList.Add(new PrintTask {Active = true, Id = 1, Name = "PrintTask1"});
taskManager.TaskList.Add(new PrintTaskOther {Active = true, Id = 2, Name = "PrintTaskOther2"});
taskManager.TaskList.Add(new PrintTask {Active = true, Id = 3, Name = "PrintTask3"});
taskManager.TaskList.Add(new PrintTask {Active = true, Id = 4, Name = "PrintTask4"});
taskManager.TaskList.Add(new PrintTaskOther {Active = true, Id = 5, Name = "PrintTaskOther5"});
}
}

The real magic that is occuring in here basically your just loading up the task objects into a List object however a few operations are overloaded that change the normal functionality of a List

public class TaskList : IList
{
private readonly List _tasks = new List();
private readonly Cache _cache = HttpRuntime.Cache;
//How long for jobs to wait before waking.
private const double sleepLength = 1;

public List Tasks
{
get
{
if (Count == 0)
{
var enumerator = _cache.GetEnumerator();
do
{
if (enumerator.Current is Task)
_tasks.Add(enumerator.Current as Task);
} while (enumerator.MoveNext());
}
return _tasks;
}
}
public void Add(Task item)
{
var task = _tasks.Find(t => t.Name == item.Name);
if (task == null)
{
_tasks.Add(item);
CacheAdd(item);
}
else
{
task.Id = item.Id;
task.Active = item.Active;
task.LastRan = item.LastRan;

CacheUpdate(item);
}
}

private void CacheUpdate(Task item)
{
_cache.Remove(item.Name);

CacheAdd(item);
}

private void CacheAdd(Task item)
{
if (_cache[item.Name] == null)
{
_cache.Add(item.Name, item, null, DateTime.Now.AddMinutes(sleepLength),
Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable,
CacheItemRemovedCallback);
}
}

public CacheItemRemovedCallback CacheItemRemovedCallback { get; set; }

Basically all it does is overrides saving the list solely to the server’s ram and writes it out to the Cache also when objects are added. It also has the Get method overrided so it will read the existing cache objects out by default for the list.

What pulls it all together to make everything work is the

public CacheItemRemovedCallback CacheItemRemovedCallback { get; set; }

This is the method that will get called when a task is removed from the cache’s dictionary. This was set in

public CacheItemRemovedCallback CacheItemRemovedCallback { get; set; }

So whenever a cache item is removed from the stack the event fires off to

public static void TaskExecuting(string key, object value, CacheItemRemovedReason reason)

Which is where we do the real execution of the job. At the end of the job we stick the item back in the cache so it will continue to loop. This is also the spot where you would put in logic to stop the service after so many iterations or it reaches some kind of predefined condition.

Updated: I have moved my source over to Assembla, you can download it directly or setup an SVN connection to view my source. Download Task Scheduler.

BloggingContext.ApplicationInstance.CompleteRequest();

kick it on DotNetKicks.com

Advertisements

Scheduled Tasks in ASP.NET!

I never would have thought there was a way to get around from needing a scheduled task to execute without implementing a windows service or a scheduled task run of a compiled executable.

Well I thought wrong.

Lately I’ve been doing alot of reading to keep up with everything .Net related and have been finding some incredible information, this has got to be one of the most profound things I have found in my ASP.NET experience.

The whole premise of a task scheduler is it needs to be atomic that every predefined interval the scheduler needs to wake up and figure out if it needs to do anything and then sleep until the next interval when it’s finished. Emulating this in ASP.NET would be impossible as far as I ever thought due to the fact that so much of all code execution is all instance based and the server itself will even sleep due to inactivity. Neither of those 2 core functionalities are desirable for a scheduler as it defeats the whole purpose of it.

This is where caching comes in. Yes, you read that right, caching. Not the standard practice of caching data for performance we’re all used to do doing but using the cache to store a cache object with a callback function and near future expiration to create our atomized tick.

Bill Beckelmen on his blog refreshes information that was spawned the whole way back in 2005 on CodeProject and improved from Microsoft’s MVP Omar Zabir’s original idea. Bill wrote Simulate a Windows Service Using ASP.NET to Run Scheduled Jobs

For the basic idea take a look over at Bill’s blog or check back as I might implement a draft of this to test it myself for a project that could potentially use it as a web driven service manager.

BloggingContext.ApplicationInstance.CompleteRequest();