Task Scheduler without the Administrator

Introduction
The scheduled task manager in the ColdFusion Administrator can be replicated outside of the administrator. You can add, update, run, and delete scheduled tasks from a tag and you can list all tasks using the unsupported ServiceFactory class.
One note: This site is on a shared hosting server and the ServiceFactory class will list ALL tasks on the server, so if you are on a shared server make an extra effort to only list and edit your tasks and no one else's.
Download Code

Screenshot of Application:
Screenshot

Part 1: List Tasks
First, we need to get a list of the tasks. This code will produce an array of structures that can be used to parse out the fields we want.
<!--- Grab all the Scheduled Tasks --->
<cflock name="alltasks" type="exclusive" timeout="10">
   
 <!--- http://www.anticlue.net/archives/000303.htm --->
    <cfscript>
        factory = CreateObject("java","coldfusion.server.ServiceFactory");
        cron_service = factory.CronService;
        services = cron_service.listALL();
    </cfscript>
</cflock>


Next, display the list to the screen. This is a temporary piece of code, we will replace with a filtered table later.
<cfdump var="#services#" label="All Scheduled Tasks">

Part 2: Add, Edit, Run and Delete a Task
The cfschedule tag is used to add, edit, run and delete scheduled tasks. CFSCHEDULE Documentation
<cfschedule
    action=
"update"
    task=
"#FORM.taskName#"
    url=
"#FORM.taskURL#"
    operation=
"httprequest"
    interval=
"#FORM.taskInterval#"
    startdate=
"#FORM.taskStartDate#"
    starttime=
"#FORM.taskStartTime#"
    publish=
"yes"
    vpath=
"#FORM.taskPublishPath#"
    file=
"#FORM.taskPublishFile#">

<cfschedule
    action="run"
    task="#FORM.taskRunName#">

<cfschedule
    action="delete"
    task="#FORM.taskDeleteName#">

Part 3: Bring it all together
Step 1: Set the default values for the form. Most importantly set the value for sitename. This variable is used to prefix all the tasks so they are associated with a single site. Since I am on a hosted server it is possible to edit and delete other site's tasks, but that would be wrong. So, we are going to prefix all the task names with our sitename and this will assure us that we only list, edit, delete and run our own tasks. Finally, initalize the message variable. This will be used to notify the user of any information.
<!--- Set Defaults and Constants --->
<cfscript>
    sitename = "brixontech.com";

    defaultTaskName = "#Replace(sitename,'.',','all')#-";
    defaultTaskURL = "http://www.#sitename#/";
    defaultStartDate = DateFormat(now());
    defaultStartTime = TimeFormat(now());
    defaultPath = GetDirectoryFromPath(GetCurrentTemplatePath());
    defaultFileName = "output.htm";
    defaultInterval = "daily";

    message = "";
</cfscript>

Step 2: Handle the edit form. This will be used to add and edit a task. The tag will handle if the save is an add or edit. We need to do a check to make sure the sitename is prefixed to the task name. Also, the attribute for URL will need to be an absolute URL. The documentation says it will accept relative URLs, but many bloggers says they have only gotten absolute URLs to work.
<!--- UPDATE Schedule --->
<cfif isdefined("FORM.taskName")>

<!--- Make sure we are only editing our own tasks --->
<!--- Prefix the task name with the site name --->

<cfif FindNoCase(defaultTaskName,FORM.taskName) EQ 0>
    <cfset FORM.taskName = sitename &
"-" & FORM.taskName>
</cfif>


<cfschedule
    action=
"update"
    task=
"#FORM.taskName#"
    url=
"#FORM.taskURL#"
    operation=
"httprequest"
    interval=
"#FORM.taskInterval#"
    startdate=
"#FORM.taskStartDate#"
    starttime=
"#FORM.taskStartTime#"
    publish=
"yes"
    path=
"#FORM.taskPublishPath#"
    file=
"#FORM.taskPublishFile#">

    <cfset message =
"Schedule Updated">
</cfif>

Step 3: Handle the delete button. This will remove the task from the task list and prevent the task from running. It does not delete the file it calls or the output file it creates.
<!--- DELETE Schedule --->
<cfif isdefined("FORM.taskDeleteName")>
    <cfschedule
    action=
"delete"
    task=
"#FORM.taskDeleteName#">

    <cfset message = "Schedule Deleted">
</cfif>

Step 4: Handle the run button. This will cause the task to run immediately.
<!--- RUN Schedule --->
<cfif isdefined("FORM.taskRunName")>
<cfschedule
    action=
"run"
    task=
"#FORM.taskRunName#">

    <cfset message = "Schedule Ran">
</cfif>

Step 5: Grab all the scheduled tasks. This array of structures will be used to display all the tasks. The ServiceFactory class is not supported and may change at any time so use with caution.
<!--- Grab all the Scheduled Tasks --->
<cflock name="#sitename#" type="exclusive" timeout="10">
    
<!--- http://www.anticlue.net/archives/000303.htm --->
    <cfscript>
        factory = CreateObject("java","coldfusion.server.ServiceFactory");
        cron_service = factory.CronService;
        services = cron_service.listALL();
    </cfscript>
</cflock>

Step 6: If the form is in edit mode, then find the selected task and set the values to our default variables.
<!--- Set Form values if Form is in edit mode. --->
<cfif isdefined("FORM.taskUpdateName")>
    <!--- Find the task to edit. --->
    <cfloop index="i" from="1" to="#ArrayLen(services)#">
        <cfif services[i].task EQ FORM.taskUpdateName>
        <cfscript>

            defaultTaskName = services[i].task;
            defaultTaskURL = services[i].url;
            defaultStartDate = services[i].start_date;
            defaultStartTime = services[i].start_time;
            defaultPath = services[i].path;
            defaultFileName = services[i].file;
            defaultInterval = services[i].interval;
        </cfscript>
        </cfif>
    </cfloop>
</cfif>

Step 7: Start the display of the page. Insert the basic HTML and CSS information.
<html>
    <head>
        <meta http-equiv=
"Content-Type" content="text/html; charset=iso-8859-1">
        <title>
My Scheduler</title>
        <style type="text/css">
            table {border:3px double #003366;}
            table th {background-color:#003366; color:#FFFFFF;}
            table td {border-bottom:1px solid #F0F0F0;}
        </style>
    </head>

    <body>

Step 8: All of the actions produce a message, so display the message.
<cfoutput><h3 style="color:green;">#message#</h3></cfoutput>

Step 9: Display the form to add and edit a task. Submit the form back to itself. I decided on using CFFORMs since there is basic input validation included. There are other attributes that can be included in a scheduled task, but this set will get you started and are the more common attributes used.
<cfform name="mySchedule" method="post" action="#CGI.SCRIPT_NAME#">
    <table cellpadding="4" cellspacing="0">
        <tr><th colspan="2">
Tasks</th></tr>
        <tr><td>
Task Name:</td><td>
            <cfinput
                name=
"taskName"
                type=
"text"
                required=
"yes"
                message=
"Task Name Required"
                value=
"#defaultTaskName#"
                size=
"40" >
        </td></tr>
        <tr><td>
URL:</td><td>
            <cfinput
                name=
"taskURL"
                type=
"text"
                required=
"yes"
                message=
"Full URL is required."
                value=
"#defaultTaskURL#"
                size=
"60">
        </td></tr>
        <tr><td>Start Date:</td><td>
            <cfinput
                name=
"taskStartDate"
                type=
"text"
                required=
"yes"
                validate=
"date"
                value=
"#defaultStartDate#"
                message=
"Enter a valid start date."
                size=
"10">
            Time:
            <cfinput
                name=
"taskStartTime"
                type=
"text"
                required=
"yes"
                validate=
"time"
                value=
"#defaultStartTime#"
                message=
"Enter a valid start time."
                size=
"10">
        </td></tr>
        <tr><td>
Publish Path:</td><td>
            <cfinput
                name=
"taskPublishPath"
                type=
"text"
                required=
"yes"
                value=
"#defaultPath#"
                message=
"Enter path for published file."
                size=
"50">
            File Name:
            <cfinput
                name=
"taskPublishFile"
                type=
"text"
                required=
"yes"
                value=
"#defaultFileName#"
                message=
"Enter file name for published file."
                size=
"10">
        </td></tr>
        
<tr><td>Interval:</td><td>
            <cfinput
                name=
"taskInterval"
                type=
"text"
                required=
"yes"
                value=
"#defaultInterval#"
                message=
"Enter number of seconds, 'once', 'daily', 'weekly', 'monthly'.">
        </td></tr>
        
<tr><td>&nbsp;</td><td>
            <cfinput
                name=
"taskSubmit"
                type=
"submit"
                value=
"Submit">
        </td></tr>
</table>
</cfform>
<br>

Step 10: Output the tasks from the array or structures we collected earlier. Note that we are only displaying tasks with our sitename prefix.
<cftry>
    <cfoutput>

    <table cellpadding="4" cellspacing="0">
        <tr>
            <th>
Run Now</th>
            <th>
Update</th>
            <th>
Task Name</th>
            <th>
Start Date</th>
            <th>
Start Time</th>
            <th>
Interval</th>
            <th>
Delete</th>
        </tr>

        <!--- Loop all the scheduled task's --->
        <cfloop index="i" from="1" to="#ArrayLen(services)#">
            <!--- Only display our tasks, the list will return all tasks on the server. --->
            <cfif FindNoCase(sitename,services[i].url)>
            <tr>
                <td>

                <form
    
                name="runNow#services[i].task#"
    
                method="post"
    
                action="#CGI.SCRIPT_NAME#"
    
                style="display:inline; margin:0;">
                    <input
                        type=
"submit"
                        name=
"runNow"
                        value=
"Run Now">
                    <input
                        type=
"hidden"
                        name=
"taskRunName"
                        value=
"#services[i].task#">
                </form>

                </td>
                <td>

                <form
                    name=
"updateTask#services[i].task#"
                    method=
"post"
                    action=
"#CGI.SCRIPT_NAME#"
                    style=
"display:inline; margin:0;">
                    <input
                        type=
"submit"
                        name=
"update"
                        value=
"Update">
                    <input
                        type=
"hidden"
                        name=
"taskUpdateName"
                        value=
"#services[i].task#">
                </form>

                </td>
                <td>
#services[i].task#</td>
                <td nowrap>
#services[i].start_date#</td>
                <td nowrap>
#services[i].start_time#</td>
                <td>
#services[i].interval#</td>
                <td>

                <form
                    name=
"deleteTask#services[i].task#"
                    method=
"post"
                    action=
"#CGI.SCRIPT_NAME#"
                    style=
"display:inline; margin:0;">
                    <input
                        type=
"submit"
                        name=
"deleteTask"
                        value=
"Delete">
                    <input
                        type=
"hidden"
                        name=
"taskDeleteName"
                        value=
"#services[i].task#">
                </form>

                </td>
            </tr>    

        </cfif>
        </cfloop>

    </table>
</cfoutput>

<cfcatch type="any">
    <cfdump var=
"#cfcatch#">
</cfcatch>
</cftry>

Step 11: End the page.
</body>
</html>

All ColdFusion Tutorials By Author: Kris Brixon
  • Building Excel Spreadsheets via XML
    Building Excel spreadsheets using Microsofts SpreadsheetML XML dialect.
    Author: Kris Brixon
    Views: 26,670
    Posted Date: Tuesday, January 24, 2006
  • Simple Suggest List using Scriptaculous
    This tutorial shows the suggest list (auto complete) idea using the built in functions in Scriptaculous with a CF data page. Working example at: http://www.brixontech.com/examples/webtwo/autocomplete/index.cfm
    Author: Kris Brixon
    Views: 20,960
    Posted Date: Sunday, July 30, 2006
  • Task Scheduler without the Administrator
    See link for tutorial and files: http://www.brixontech.com/examples/scheduler/index.cfm The scheduled task manager in the ColdFusion Administrator can be replicated outside of the administrator. You can add, update, run, and delete scheduled tasks from a tag and you can list all tasks using the unsupported ServiceFactory class.
    Author: Kris Brixon
    Views: 17,924
    Posted Date: Friday, August 11, 2006
  • Easy Table Sort / Page using AJAX
    Table sort and paging using AJAX calls to fill a div that will be the container for the table. See the following page for a live demo. http://www.brixontech.com/examples/table/index.cfm
    Author: Kris Brixon
    Views: 27,818
    Posted Date: Sunday, August 13, 2006
Download the EasyCFM.COM Browser Toolbar!