Click here to Skip to main content
Click here to Skip to main content

Guadagno Task Scheduler

By , 17 Oct 2008
 

Contents

Introduction

The Guadagno Task Scheduler is a Windows Service application that allows you to create tasks that can be scheduled to run in a variety of different times and patterns. The tasks are .NET v2.0 assemblies that inherit from the ITaskPlugin interface. For more information on the ITaskPlugin interface, please visit the CodeProject article at http://www.codeproject.com/KB/macros/TaskPlugin.aspx or the project homepage on SourceForge at http://taskplugin.sourceforge.net. This project has been released to the community. Visit the CodePlex project at http://www.codeplex.com/taskservice.

Application

The Guadagno Task Scheduler will look for tasks (plug-ins) to execute by searching the directory specified in the PluginPath configuration section (see the Configuration section). If this value is not found, the default directory of Plugins folder beneath the root of the installation will be used.

Folder Structure

Folder
Installation directory Contains the task scheduler and support files.
\Logs Contains the log files for the task scheduler and plug-ins.
\Plugins Contains the plug-ins (the default directory that the task scheduler looks in for plug-ins).

Configuration File

The Guadagno Task Scheduler does not use the typical .NET configuration file; the application uses an XML file for configuration that derives from the Guadagno.Utilities.Configuration.ConfigurationBase class. Look for an article on this class in the near future. This class allows for you to dynamically change the configuration or provide different configuration parameters depending on the name of the machine the application is running on.

Configuration File Schema

<application.settings stage="auto">
    <hosts>
        <host name="uatMachinename" stage="uat" comment="" />                
        <host name="prodMachinename" stage="prod" comment="" />                
    </hosts>
    <stage name="default">
    <!-- Default configuration settings -->
    </stage>
    <stage name="uat">
    <!-- UAT configuration settings -->
    </stage>
    <stage name="prod">
    <!-- Production configuration settings -->
    </stage>
</application.settings>

The root element of the configuration file is the <application.settings> element. <application.settings> has 2+ child nodes: <hosts> and <stage>. <application.settings> has an attribute named stage which indicates which stage element to load. The <stage> attribute can contain one of the following values:

<application.settings stage="Value">
auto A value of auto reads the machine name; that is the service is running on and looks in the <hosts> section for the appropriate stage to load.
stage name Explicitly loads the stage.

The default stage is always read and used to provide the default values for the properties of the application. After the default section is read, the configuration class will load the configuration based on the stage attribute for the <application.settings> element.

The PluginPath Property

This property is used to instruct the Guadagno Task Scheduler the directory you wish to use. This property overrides the default directory of \Plugins underneath the installation directory.

The log4net Property

This property is used to provide the log4net configuration for the Guadagno Task Scheduler. The basic configuration provides a number of different log4net appenders, rolling file, Telnet, and SMTP.

Creating a Plug-In or Task

Creating a plug-in or task is as easy as implementing the ITaskPlugin interface. This interface is provided in the .NET assembly TaskPluginInterface.dll.

ITaskPlugin Interface

A sample implementation of the ITaskPlugin interface. For a more complete example, please refer to the article: 'A Flexible .NET Plug-in Architecture, by Joseph Guadagno'.

[TaskPluginInterface.Plugin(PluginType.Unknown)]
public class PluginShell : ITaskPlugin
{
    #region ITaskPlugin Members
    #region ITaskPlugin Properties

    public string Name
    {
        get { return "My sample Task"; }
    }

    public string Description
    {
        get { return "My first test plug-in"; }
    }

    public string Extension
    {
        get { return "The extension that this plug-in handles (not implemented)"; }
    }
    
    public string ExtensionDescription
    {
        get { return "A description of the extension (not implemented)"; }
    }
    
    public string Version
    {
        get { return "1.0.0.1"; }
    }
    
    public string Author
    {
        get { return "Joseph Guadagno"; }
    }
    
    public List<ischeduleditem> Schedule
    {
        get { return m_Schedule; }
    }

    #endregion ITaskPlugin Properties

    #region ITaskPlugin Methods

    public ExecuteResult Execute()
    {

        try
        {
            // Setup the Progress Information
            m_Progress.TotalTasks = 1;
            m_Progress.TotalItems = 1;
            m_Progress.CurrentTask = 0;
            m_Progress.CurrentItem = 0;
            m_Cancel = false;
        
            m_Log.Debug(Properties.Resources.Execute_Started);
        
            // If the EventStart event has been subscribed to let's fire it.
            if (EventStart != null)
                EventStart(this, new PluginEventArgs(m_Progress, 
                           "Starting the task.", null));
        
            DoWork();
        
            // If the EventStart event has been subscribed to let's fire it.
            if (EventEnd != null)
            {
                if (m_Cancel)
                {
                    EventEnd(this, new PluginEventArgs(m_Progress, 
                             "Task execution was cancelled.", null));
                }
                else
                {
                    EventEnd(this, new PluginEventArgs(m_Progress, 
                             "Task execution is complete.", null));
                }
            }
    
          // Exit 
          if (m_Cancel)
          {
              m_Log.DebugFormat(Properties.Resources.Execute_Ended, 
                                ExecuteResult.Cancelled);
              return ExecuteResult.Cancelled;
          }
          else
          {
              m_Log.DebugFormat(Properties.Resources.Execute_Ended, 
                                ExecuteResult.Ok);
              return ExecuteResult.Ok;
          }
      }
      catch (Exception ex)
      {
          if (EventExceptionOccurred != null)
              EventExceptionOccurred(this, new PluginEventArgs(m_Progress, 
                                     "", ex));
    
          // Exit with an Exception
          return ExecuteResult.Exception;
      }

    }

    public bool Cancel()
    {
        m_Log.Debug(Properties.Resources.CancelMethodExecuted);
        m_Cancel = true;
        return true;
    }
    #endregion ITaskPlugin Methods
    
    #region ITaskPlugin Events
    public event OnStart EventStart;
    public event OnEnd EventEnd;
    public event OnProcessing EventProcessing;
    public event OnExceptionOccurred EventExceptionOccurred;
    #endregion ITaskPlugin Events
    
    #endregion

    #region Private Methods
    
    /// <summary>
    /// Sample subroutine to demonstrate how to execute work.
    /// </summary>
    /// <returns>
    private ExecuteResult DoWork()
    {
    
        int longLoop = 120;
        // Reset the currentItem counter
        m_Progress.CurrentItem = 0;
        // Set the numbers of items to process
        m_Progress.TotalItems = longLoop;
    
        m_Log.Debug(Properties.Resources.StartingToDoWork);
    
        for (int x = 1; x < longLoop; x++)
        {
            // Just Sleep for a half of a second
            System.Threading.Thread.Sleep(50);
    
            m_Log.DebugFormat(Properties.Resources.WorkingOn, x);
    
            // Update the current item
            m_Progress.CurrentItem = x;
            if (EventProcessing != null)
            {
                PluginEventArgs evt = new PluginEventArgs(m_Progress, 
                                          "Working", null);
                EventProcessing(this, evt);
                if (evt.Cancel == true)
                {
                    m_Log.Debug(Properties.Resources.CancelRequestRecieved);
                    m_Cancel = true;
                    break;
                }
            }
        }
    
        if (m_Cancel)
            return ExecuteResult.Cancelled;
        else
        {
            m_Progress.CurrentTask++;
            return ExecuteResult.Ok;
        }
    
    }
    
    #endregion Private Methods
}

Configuration

The Schedule Property

The schedule for each task is provided by the task itself. Once the Task Scheduler "discovers" a task within its plug-in directory, it will retrieve the schedule by examining the schedule property. The scheduling component uses the .NET scheduled timer library written by Andrew Brummer (see reference below).

The plug-in can "hard code" the schedule, which is not recommended, or load it from a configuration file. To make it easier for placing the schedule in a configuration file, I encapsulated the different schedule types (IScheduledItem) available from the .NET scheduled timer library into an XML file and provided a utility function, TaskPluginInterface.ScheduleConfig.Load(), to parse the configuration.

An example configuration file:

<Schedule>
    <ScheduledTime Base="ByMinute" Offset="1,0" />
    <SimpleInterval StartTime="1/7/08" Interval="5" EndTime="1/15/08"/>
    <SimpleInterval StartTime="1/1/08" Interval="15" />
    <SimpleInterval StartTime="1/2/08" Interval="20" Count="5"/>
    <SingleEvent EventTime="1/15/08" />
    <EventQueue>
        <ScheduledTime Base="ByMinute" Offset="15,0" />
        <ScheduledTime Base="ByMinute" Offset="30,0" />
    </EventQueue>
    <BlockWrapper Base="Daily" BeginOffset="6:00 AM" EndOffset="5:00 PM">
        <ScheduledTime Base="ByMinute" Offset="15,0" />
    </BlockWrapper>
</Schedule>

For more details on TaskPluginInterface, please checkout the CodeProject article at http://www.codeproject.com/KB/macros/TaskPlugin.aspx or the project page at http://taskplugin.sourceforge.net.

Next Steps / Future Features

  • Refresh / reload the plug-ins when there are directory changes
  • Enable the plug-ins to have / use their own log files

History

Version Date What was done
1.0.0.1 5/14/07 Created the initial release of the file.

References

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Joseph Guadagno
Web Developer
United States United States
Member
I have been in software development for about 15 years or so. I started out with a small book on QuickBASIC, then moved the Visual Basic for DOS, then Visual Basic for Windows, then Visual Basic .NET and eventually Visual C#. When I am not working at my full time job I donate my time to several community efforts like:
 
Former President of INETA North America, currently Vice President.
President of the Southeast Valley .NET User Group (SEVDNUG) in Chandler, AZ.
Serving on my City's Parks and Recreation board.
 
I have or have had the following "MVP" awards:
  • Visual Basic MVP in 1996
  • C# MVP since 2009
  • Telerik MVP since 2010
I maintain a Open Source project on CodePlex which wraps the Bing API called BingSharp.
 
I also help / organize or participate in several community events:
  • Desert Code Camp
  • AZGiveCamp
  • Organizer for the 1st Time MVP event at the MVP Summit
  • MVP 2 MVP Sessions at MVP Summit.
  • Awesome bean pusher at GeekGive at the MVP Summit.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralGuadagno.Utilities.Configuration.ConfigurationBasememberwoocareer1 Aug '10 - 21:45 
Guadagno.Utilities.Configuration.ConfigurationBase is not supply
GeneralGPL Task SchedulermemberDanilo Corallo17 Oct '08 - 5:19 
Here a GPL solution:
http://www.codeproject.com/KB/database/SQLAgent.aspx
GeneralRe: GPL Task SchedulermemberJoseph Guadagno17 Oct '08 - 5:57 
Yeah I have seen this before. This is geared towards SQL jobs. My solution works with anything. You can create SQL jobs, data feeds, security scans, essentially anything that you can create a .NET application for.
 
Here are some of my articles.
Hope this helps!
Joseph Guadagno
http://www.josephguadagno.net

GeneralRe: GPL Task SchedulermemberDanilo Corallo17 Oct '08 - 6:15 
No it's not! It's a generic scheduler with plugins support. The only thing that is tailored to SQL is the title label in the service controller!
Kind Regards,
D.
GeneralMissingmemberMadmaximus5 Jun '07 - 6:13 
Where is the source code????
GeneralRe: MissingmemberJoseph Guadagno5 Jun '07 - 8:42 
The source code has not been released. I am not sure if I am going to turn this into a commercial product or not.
 
Here are some of my articles.
Hope this helps!
Joseph Guadagno
http://www.josephguadagno.net

GeneralRe: MissingmemberESTANNY1 Oct '07 - 1:14 
It is a pity. I don't think that this community is not the right target for to test your commercial applications. I suggest that you provide the source, there will come more feedback and eventually you will sell your product anyway.
 
Good luck with it.
GeneralRe: MissingmemberDewey26 Feb '08 - 17:50 
You have to be joking!
 
Commercial product?
 
Get real!
GeneralRe: MissingmemberJoseph Guadagno17 Oct '08 - 4:04 
This product was release to the open source community at http://www.codeplex.com/TaskService
 
Here are some of my articles.
Hope this helps!
Joseph Guadagno
http://www.josephguadagno.net

GeneralDo NOT install this this!!!!!!!memberrob996624 May '07 - 16:44 
Not only does it load tons of instances of notepad, but it will NOT uninstall.
 
www.vbutils.com
www.dnconsultants.com
GeneralRe: Do NOT install this this!!!!!!!memberJoseph Guadagno24 May '07 - 17:50 
It only loads tons of instances of Notepad if you install the RunCommand plug-in. Which by default is configured to execute every minute to demonstrate the scheduling and the Command line loading of an application.
 
As far as the uninstall goes, I have tried it on over 5 machines and have not had any issues with installing or uninstalling the application. Can you please provide some feedback as to any error messages that you are getting.
 
I am sorry that you have had trouble with this application / article.
 
Hope this helps!
Joseph Guadagno
http://www.josephguadagno.net

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 17 Oct 2008
Article Copyright 2007 by Joseph Guadagno
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid