Blog

28Aug
2006
GetScheduledTasks() Function Returns Scheduled Task List

<cfschedule> is used to define and run ColdFusion scheduled tasks. For some reason the tag does not return a list of defined tasks, and a user on cf-talk asked for this functionality recently. So, until we update <cfschedule>, here is a UDF that returns a query containing the details about all scheduled tasks.

The bulk of this code (the regular expressions, funky nested looping, and so on) are the work of Michael Dinowitz (and I have retained his warnings about not doing what he is about to do).

view plain print about
1<!--- Obtain scheduled tasks details --->
2<cffunction name="GetScheduledTasks" returntype="query" output="no">
3
4    <!--- Local vars --->
5    <cfset var tasks="">
6    <cfset var result=QueryNew('path,file,resolveurl,url,publish,password,operation,username,interval,start_date,http_port,task,http_proxy_port,proxy_server,disabled,start_time,request_time_out')>
7    <cfset var OuterStart="">
8    <cfset var InnerStart="">
9    <cfset var qRETest="">
10    <cfset var qRETestinner="">
11    <cfset var ScheduleItem="">
12
13    <!--- This call is undocumented --->
14    <cfsavecontent variable="tasks">
15        <cfschedule action="run" task="__list">
16    </cfsavecontent>
17
18    <!--- The start for each schedule entry --->
19    <cfset OuterStart=1>
20
21    <!--- Be super careful when using an infinite loop in this manner.
22        Actually, never use an infinite loop in this manner. --->

23    <cfloop condition="OuterStart">
24        <!--- Each schedule item is a text string followed by an = followed by a double {.
25            The end of the item also has a double }
26            Getting only the elements in an item removed the need for a negative lookahead later --->

27        <cfset qRETest=REFind('\w+={{(.+?})}}', tasks, OuterStart, 1)>
28        <!--- If there is a result, use it.
29            Otherwise break out of the loop. VERY IMPORTANT!!! --->

30        <cfif qRETest.Pos[1]>
31            <!--- This is the string containing all of the
32                elements in a schedule item --->

33            <cfset ScheduleItem=Mid(tasks, qRETest.Pos[2], qRETest.len[2])>
34            <!--- Set the start past the schedule item found --->
35            <cfset OuterStart=qRETest.Pos[2]+qRETest.len[2]>
36
37            <!--- The start for each element of a schedule item --->
38            <cfset InnerStart=1>
39            <!--- Add a row. We don't have so specify as we'll be
40                adding 1 per schedule item --->

41            <cfset QueryAddRow(result)>
42        
43            <!--- Be super careful when using an infinite loop in this manner.
44                Actually, never use an infinite loop in this manner. --->

45            <cfloop condition="InnerStart">
46                <!--- A schedule element is text followed by an = followed by
47                    a value inside of {}. Even though the schedule item string
48                    can be seen as a list, we don't know if there will be a
49                    comma inside one of the elements so we're doing it the
50                    hard but safe way. --->

51                <cfset qRETestinner=REFind('(\w+)={([^}]*)}', ScheduleItem, InnerStart, 1)>
52    
53                <!--- If there is a result, use it.
54                    Otherwise break out of the loop. VERY IMPORTANT!!! --->

55                <cfif qRETestinner.Pos[1]>
56                    <!--- The QuerySetCell will automatically assign the value to the last row added so no need to specify row. The second element of the RegEx return is the column name and the third is the value--->
57                    <cfset QuerySetCell(result,
58                                        Mid(ScheduleItem, qRETestinner.Pos[2], qRETestinner.len[2]),
59                                        Mid(ScheduleItem, qRETestinner.Pos[3], qRETestinner.len[3]))
>

60                    <!--- Set the start past the schedule element found --->
61                    <cfset InnerStart=qRETestinner.Pos[1]+qRETestinner.len[1]>
62                <cfelse>
63                    <!--- Break out of our inner infinite loop --->
64                    <cfbreak>
65                </cfif>
66            </cfloop>
67        <cfelse>
68            <!--- Break out of our inner infinite loop --->
69            <cfbreak>
70        </cfif>
71    </cfloop>
72
73    <cfreturn result>
74
75</cffunction>

Comments (14)



  • Sami Hoda

    Is this something you can ask for in the next version of ColdFusion? (hint, hint)

    #1Posted by Sami Hoda | Aug 29, 2006, 02:16 AM
  • Mitfahrzentrale

    Hi,
    for some reason the UDF gives an empty result set on CFMX 6.1.
    But the CF-Administrator shows my scheduled tasks.
    Does it only work on CFMX 7 ?

    Kind regards
    Thorsten

  • Ben Forta

    Sami, yep, I've asked for this enhancement.

    Thorsten. Run that cfschedule line by itself and see if it returns data.

    --- Ben

    #3Posted by Ben Forta | Aug 29, 2006, 08:04 AM
  • King AdRock

    Ben,

    What do you use for regular expression strings?

    #4Posted by King AdRock | Aug 29, 2006, 09:57 AM
  • Ben Forta

    KAR, I have no idea what you are asking, sorry.

    --- Ben

    #5Posted by Ben Forta | Aug 29, 2006, 10:00 AM
  • Michael Dinowitz

    ColdFusion has 4 RegEx functions. 2 for find (REFind/REFindNoCase) and 2 for replace (REReplace/REReplaceNoCase). Most of the RegEx syntax are allowed within these functions and this is what was used in the example. Negative lookaheads are possible and were the original thought until a larger pattern was found and simpler code was written.

    If you need more RegEx power for things like positive and negative look-behinds, you can always leverage the power of the Java RegEx engine directly using CFOBJECT or CreateObject().

  • Rahul Narula

    The above UDF work for me on CF 7.0.1

    But I use this undocumented feature to get me the array of all defined scheduled task (without too much regex stuff )

    <cfscript>
    alltask=ArrayNew(1);
    taskService=createobject('java','coldfusion.server.ServiceFactory').getCronService();
    alltask=taskservice.listall();
    </cfscript>
    <cfdump var="#alltask#">

  • Michael Dinowitz

    So when is Adobe going to stop giving us all this good stuff in an undocumented factory and instead document it? ;)

  • Patrick Whittingham

    Ben/Michael/Rahul -

    That's a cool 'features' of servicefactory. Can one get that kind of information for ALL of cfquery(s), just like one sees in debug mode for a template. I need all of the queries/sql without giving the list of cfquery names. I've seen 1 hardcoded sql via servicefactory,but not all of the cfquery sq for a template. I need the sql,recordcount and time.

    #9Posted by Patrick Whittingham | Aug 29, 2006, 08:53 PM
  • Russ Spivey

    that is a rad bit of code Rahul!

  • Don Vawter

    Just a note. In CF 8 you need to add a "paused" column to the query.

    #11Posted by Don Vawter | Sep 12, 2009, 11:01 PM
  • Charlie Arehart

    I found that in CF9 I needed to not only add paused (as Don mentioned) but also last_run and end_time. (We're talking about just adding them to the end of the querynew function on line 7.)

  • Don Vawter

    For cf9 you can use the CronService.listAll method in coldfusion.server.ServiceFactory

    http://stackoverflow.com/questions/2320396/how-to-...

  • Geoff Bowers

    Railo 3+ and CF10+ now offer a **list** action: <cfschedule action="list" returnvariable="qTasks">