Click here to Skip to main content
Click here to Skip to main content
Go to top

Guadagno Task Scheduler

, 17 Oct 2008
Rate this:
Please Sign up or sign in to vote.
The Guadagno Task Scheduler is a Windows Service application that allows you to create tasks (.NET assemblies) that can be executed at different intervals.

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)

Share

About the Author

Joseph Guadagno
Web Developer
United States United States
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.
Follow on   Twitter

You may also be interested in...

Comments and Discussions

 
GeneralGuadagno.Utilities.Configuration.ConfigurationBase Pinmemberwoocareer1-Aug-10 21:45 
GeneralGPL Task Scheduler PinmemberDanilo Corallo17-Oct-08 5:19 
GeneralRe: GPL Task Scheduler PinmemberJoseph Guadagno17-Oct-08 5:57 
GeneralRe: GPL Task Scheduler PinmemberDanilo Corallo17-Oct-08 6:15 
GeneralMissing PinmemberMadmaximus5-Jun-07 6:13 
GeneralRe: Missing PinmemberJoseph Guadagno5-Jun-07 8:42 
GeneralRe: Missing PinmemberESTANNY1-Oct-07 1:14 
GeneralRe: Missing PinmemberDewey26-Feb-08 17:50 
GeneralRe: Missing PinmemberJoseph Guadagno17-Oct-08 4:04 
GeneralDo NOT install this this!!!!!!! Pinmemberrob996624-May-07 16:44 
GeneralRe: Do NOT install this this!!!!!!! PinmemberJoseph Guadagno24-May-07 17:50 

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

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

| Advertise | Privacy | Mobile
Web04 | 2.8.140926.1 | Last Updated 17 Oct 2008
Article Copyright 2007 by Joseph Guadagno
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid