I have a CF10 scheduled task set to run every 2 minutes, though sometimes it takes longer than that to finish. I set up an application variable to prevent the job from running in the event an older job takes longer than 2 minutes. I don't want the scheduled task to overlap. This appears to work. Here is an example of my scheduled task:
<cfoutput>
Scheduled Task hit: #NOW()#<br />
</cfoutput>
<cfif NOT StructKeyExists(application,"BigJob")>
<!--- Init the BigJob --->
<cfset application.BigJob = { isProcessing = FALSE }>
</cfif>
<!--- Is a BigJob already running? --->
<cfif application.BigJob.isProcessing>
<!--- yes it is, abort. --->
<cfoutput>
A BigJob is already in process.
</cfoutput>
<cfabort>
<cfelse>
<!--- No it isn't, start processing. --->
<cfset application.BigJob.isProcessing = TRUE>
<cfoutput>
Processing has begun: #NOW()#<br />
</cfoutput>
</cfif>
<cfscript>
// sleep for 15 seconds. To simulate processing.
sleep(15000);
</cfscript>
<cfoutput>
Scheduled Task complete: #NOW()#
</cfoutput>
<cfset application.BigJob.isProcessing = FALSE>
If I hit this in my browser, I get this output:
Scheduled Task hit: {ts '2013-05-10 16:02:10'}
Processing has begun: {ts '2013-05-10 16:02:10'}
Scheduled Task complete: {ts '2013-05-10 16:02:25'}
If I hit it again in another tab of the same browser 5 seconds later, 10 seconds before the first job finishes, I get this:
Scheduled Task hit: {ts '2013-05-10 16:02:25'}
Processing has begun: {ts '2013-05-10 16:02:25'}
Scheduled Task complete: {ts '2013-05-10 16:02:40'}
This suggests that CF waits for one request to finish before starting the next (note the start and end times).
If I hit the CFM in a different browser, 5 seconds after hitting the first one, I get this expected output:
Scheduled Task hit: {ts '2013-05-10 16:02:18'}
A BigJob is already in process.
My problem is, it appears as if the CFSCHEDULER does not wait for a previous request to finish. CF does wait if the request came from same browser, but it doesn't appear to wait if it's coming from a scheduled task. In CF9, I thought it did.
Is there a better way to prevent scheduled tasks from overlapping in CF10? What is a google-able term for the thing that is preventing my browser from hitting the same page twice? Am I correct that CF9 did wait for a previous task to finish and CF10 does not?
In my tests, ColdFusion 9 does not execute a task if it is already running. I created a task called "test" that sleeps for 4 minutes but is scheduled to run every 2 minutes. You can see the scheduler log results below:
"Information","scheduler-2","05/10/13","14:34:00",,"[test] Executing at Fri May 10 14:34:00 PDT 2013"
"Information","scheduler-2","05/10/13","14:38:00",,"[test] Rescheduling for :Fri May 10 14:40:00 PDT 2013 Now: Fri May 10 14:38:00 PDT 2013"
"Information","scheduler-0","05/10/13","14:40:00",,"[test] Executing at Fri May 10 14:40:00 PDT 2013"
"Information","scheduler-0","05/10/13","14:44:00",,"[test] Rescheduling for :Fri May 10 14:46:00 PDT 2013 Now: Fri May 10 14:44:00 PDT 2013"
"Information","scheduler-3","05/10/13","14:46:00",,"[test] Executing at Fri May 10 14:46:00 PDT 2013"
Each time, the task took 4 minutes to run and then it was rescheduled for 2 minutes in the future. So the effective interval between runs was actually 6 minutes.
Here is the code I used in the CFM page being executed:
<cfsetting requesttimeout="5000">
<cfscript>
sleep(240000);
</cfscript>
Here are the task settings I used:
If you are getting overlapping executions of scheduled tasks in ColdFusion 10, then as #Leigh mentioned, Ben Nadel's <cflock> solution is a simple way to prevent those overlaps.
Related
I have an application which has different types of users. I need to set sessionTimeout based on user type. For example admin 30 minutes, user 10 minutes. To do this, I gave a default sessionTimeout of 30 minutes in application.cfc
<cfcomponent output="false" extends="org.corfield.framework">
<cfset this.applicationTimeout = createTimeSpan(1,0,0,0) />
<cfset this.sessionManagement = true />
<cfset this.sessionTimeout = createTimeSpan(0,0,30,0) />
.............
............
</cfcomponent>
When I dump the application variables I can see sessionTimeout is 600 which is correct. Now in the onRequestStart method, I wrote a code to check the loggedIn user type and set the sessionTimeout accordingly.
<cfif StructKeyExists(session,"user") AND ListLast(CGI.HTTP_REFERER,"/") EQ "login.cfm" >
<cfif session.user.userType EQ "GSA">
<cfset this.sessionTimeout = createTimeSpan(0,0,10,0) />
</cfif>
</cfif>
After this when I dump application variables, sessionTimeout is showing in days not in seconds. And also session is not getting ended after 10 minutes.
Can someone help on this? How to implement two different sessionTimeout in an application? Also why it is showing the sessionTimeout in days instead of seconds once I set the sessionTimeout again?
I don't believe there is any way to modify this scope metadata from inside one of these functions: onApplicationStart, onSessionStart or onRequestStart. Meaning you can't set this.sessionTimeout in any of those methods.
I was recently looking into this ColdFusion 11: Changing Application "this" Scope metadata from different functions in extended Application.cfc. However metadata is set for every request made by ColdFusion. Meaning you can try an approach like mentioned in this article, by Ben Nadel, and move the logic that sets the timeout out of onRequest() and onto the this scope and try creating dynamic session timeouts.
Delaying ColdFusion Session Persistence Until User Logs In
You are probably going to have to get creative in figuring out which user is logging in at that point though. ( Even if authentication occurs later ... any harm in setting a timeout?)
Session timeouts are common for all users. The timeout duration is set application-wide when the first request comes.
I think the short answer is, you cannot set two different session timeout durations.
Here is one method you can use. It's kind of creating your own session management client side, but it would allow for custom session timeouts per user role.
Create a timestamp in the session scope that is initially set to the current time a user logs on to your app. In your app's client JavaScript, create a timer that calls a function every minute or so that in turn calls a server side function to see how much time has elapsed since the last recorded timestamp for that user. If the time elapsed reaches the maximum allowed for that user's role, use the JavaScript function to logout the user.
With this method you reset the timestamp each time the user "interacts" with the app (runs a script, calls a cfc library function, etc.), such that the user does not get logged out while actively using the app. The user is only logged out after "x" minutes of inactivity that you define, and the function you call on the server side can further define what that number is per user role.
I've used this in railo but i think it applies to coldfusion too.
getPageContext().getSession().setMaxInactiveInterval(javaCast("int", 60));
It basically sets the session time out value of the currently running request to 60 something (i can't remember if it's in minutes or seconds)
With scheduled tasks, but none that are chained, I get the below error in my exception.log when starting Adobe ColdFusion 10 services (on Windows). How do I troubleshoot this back to the source of the error?
"Error","DefaultQuartzScheduler_Worker-2","09/15/14","15:12:02",,"Task invokehandler could not be chained"
java.lang.Exception: Task invokehandler could not be chained
at coldfusion.scheduling.CronTask.onCompleteTask(CronTask.java:214)
at coldfusion.scheduling.CronTask.execute(CronTask.java:130)
at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
Note: I get three nearly identical errors the only difference is where it says "Worker-2" in the error above, I also get "Worker-1" and "Worker-3"
There are a couple of things you could do here. You could write a ColdFusion page that checks the health of your scheduled tasks and monitor that page manually (Check health of scheduled tasks). Of course that code could also be a scheduled task itself. Or you can add logging to your scheduled task(s) at various points to "see" what they are doing. I prefer the latter.
For the simplest of logging you can check the "Enable Logging for Scheduled Tasks" in the ColdFusion administrator, under the Logging Settings Page. This will create a new log file named scheduler.log. This option will report when a task is started, when it ends, if it errors, etc. BUT this log still only contains generic information such as the task's name and the thread name used to execute the task. This in itself probably won't help you much but it will show you which thread is running which task.
For more detailed information you will need to add your own logging within your scheduled task(s) code. I typically place the logging code at main points during the code's execution; "started", "retrieving data", "updating database", "writing file", "done", etc. Then whenever you need to check what happened with the task you just read your log file to have a look.
Here is some sample code:
<cftry>
<cflog file="your_file_name" type="information" text="Starting scheduled job xyz">
... code ...
<cflog file="your_file_name" type="information" text="Step 123">
... code ...
<cflog file="your_file_name" type="information" text="Step 456">
... code ...
<cflog file="your_file_name" type="information" text="Scheduled job xyz finished successfully">
<cfcatch type="any">
<cflog file="your_file_name" type="error" text="Error: #cfcatch.Type#, #cfcatch.Message#, #cfcatch.Detail#">
<!--- I usually send an email to myself for errors as well using <cfmail ... /> --->
</cfcatch>
</cftry>
And here is a link to the documentation for the <cflog> tag.
I found the same error for Task invokehandler could not be chained in exception logs after performing an upgrade to a newer ColdFusion version using the migration wizard. This appears to have been caused by the insertion of the text invokehandler during Scheduled Tasks import.
Remedy this behavior with the following steps:
Log in to the ColdFusion Administrator
Edit each scheduled task (click the pencil icon) and perform the following:
Scroll down and click Show Advanced Settings
Remove the text invokedhandler from the On Complete field
Click Submit
The errors should cease at this point after editing all your scheduled tasks.
I have a CF10 scheduled task set to run every 2 minutes, though sometimes it takes longer than that to finish. I set up an application variable to prevent the job from running in the event an older job takes longer than 2 minutes. I don't want the scheduled task to overlap. This appears to work. Here is an example of my scheduled task:
<cfoutput>
Scheduled Task hit: #NOW()#<br />
</cfoutput>
<cfif NOT StructKeyExists(application,"BigJob")>
<!--- Init the BigJob --->
<cfset application.BigJob = { isProcessing = FALSE }>
</cfif>
<!--- Is a BigJob already running? --->
<cfif application.BigJob.isProcessing>
<!--- yes it is, abort. --->
<cfoutput>
A BigJob is already in process.
</cfoutput>
<cfabort>
<cfelse>
<!--- No it isn't, start processing. --->
<cfset application.BigJob.isProcessing = TRUE>
<cfoutput>
Processing has begun: #NOW()#<br />
</cfoutput>
</cfif>
<cfscript>
// sleep for 15 seconds. To simulate processing.
sleep(15000);
</cfscript>
<cfoutput>
Scheduled Task complete: #NOW()#
</cfoutput>
<cfset application.BigJob.isProcessing = FALSE>
If I hit this in my browser, I get this output:
Scheduled Task hit: {ts '2013-05-10 16:02:10'}
Processing has begun: {ts '2013-05-10 16:02:10'}
Scheduled Task complete: {ts '2013-05-10 16:02:25'}
If I hit it again in another tab of the same browser 5 seconds later, 10 seconds before the first job finishes, I get this:
Scheduled Task hit: {ts '2013-05-10 16:02:25'}
Processing has begun: {ts '2013-05-10 16:02:25'}
Scheduled Task complete: {ts '2013-05-10 16:02:40'}
This suggests that CF waits for one request to finish before starting the next (note the start and end times).
If I hit the CFM in a different browser, 5 seconds after hitting the first one, I get this expected output:
Scheduled Task hit: {ts '2013-05-10 16:02:18'}
A BigJob is already in process.
My problem is, it appears as if the CFSCHEDULER does not wait for a previous request to finish. CF does wait if the request came from same browser, but it doesn't appear to wait if it's coming from a scheduled task. In CF9, I thought it did.
Is there a better way to prevent scheduled tasks from overlapping in CF10? What is a google-able term for the thing that is preventing my browser from hitting the same page twice? Am I correct that CF9 did wait for a previous task to finish and CF10 does not?
In my tests, ColdFusion 9 does not execute a task if it is already running. I created a task called "test" that sleeps for 4 minutes but is scheduled to run every 2 minutes. You can see the scheduler log results below:
"Information","scheduler-2","05/10/13","14:34:00",,"[test] Executing at Fri May 10 14:34:00 PDT 2013"
"Information","scheduler-2","05/10/13","14:38:00",,"[test] Rescheduling for :Fri May 10 14:40:00 PDT 2013 Now: Fri May 10 14:38:00 PDT 2013"
"Information","scheduler-0","05/10/13","14:40:00",,"[test] Executing at Fri May 10 14:40:00 PDT 2013"
"Information","scheduler-0","05/10/13","14:44:00",,"[test] Rescheduling for :Fri May 10 14:46:00 PDT 2013 Now: Fri May 10 14:44:00 PDT 2013"
"Information","scheduler-3","05/10/13","14:46:00",,"[test] Executing at Fri May 10 14:46:00 PDT 2013"
Each time, the task took 4 minutes to run and then it was rescheduled for 2 minutes in the future. So the effective interval between runs was actually 6 minutes.
Here is the code I used in the CFM page being executed:
<cfsetting requesttimeout="5000">
<cfscript>
sleep(240000);
</cfscript>
Here are the task settings I used:
If you are getting overlapping executions of scheduled tasks in ColdFusion 10, then as #Leigh mentioned, Ben Nadel's <cflock> solution is a simple way to prevent those overlaps.
I need some help with creating an automatic timing script with ColdFusion. My assumption is cfschedule and conditionals will be used to get this done. I am looking for something automatic, not on browser loads.
Anyways, every 60 minutes I would like to see if a page on one of my servers (http://www.mysite.com/page.php) is working or not.
If the page is down when it is checked, then it will check again in 5 minutes to see if the page is back up.
If it is not back up, then I am sent an e-mail to email#mysite.com. If it is back up, then no action is required and we start the 60 minute cycle check again.
Can anybody please help me with this?
Mike,
Not sure what version of CFML you are on but you could certainly set a scheduled task in your cf-administrator (I prefer the admin over cfschedule ... personal preference is all) to run your "site checker" script/page each hour and then, in that script/page, you could do something along the lines of:
<cfhttp url="http://mysite.com/ping-this-mofo.cfm" method="get" >
<cfif cfhttp.statusCode neq "200 OK">
<!--- some code to sleep for 5 minutes or a one-time cfschedule to check the site again --->
<cfschedule action="run" task="my-task-thingy" url="script-that-will-run" interval="once" startDate="today" startTime="5 minutes from now" />
</cfif>
Then, when that "sub-scheduled task" runs, you could check for the server being active and, if it isn't, fire off a an email via cfmail.
Our CF server occasionally stops processing mail. This is problematic, as many of our clients depend on it.
We found suggestions online that mention zero-byte files in the undeliverable folder, so I created a task that removes them every three minutes. However, the stoppage has occurred again.
I am looking for suggestions for diagnosing and fixing this issue.
CF 8 standard
Win2k3
Added:
There are no errors in the mail log at the time the queue fails
We have not tried to run this without using the queue, due to the large amount of mail we send
Added 2:
It does not seem to be a problem with any of the files in the spool folder. When we restart the mail queue, they all seem to process correctly.
Added 3:
We are not using attachments.
What we ended up doing:
I wrote two scheduled tasks. The first checked to see if there were any messages in the queue folder older than n minues (currently set to 30). The second reset the queue every night during low usage.
Unfortunately, we never really discovered why the queue would come off the rails, but it only seems to happen when we use Exchange -- other mail servers we've tried do not have this issue.
Edit: I was asked to post my code, so here's the one to restart when old mail is found:
<cfdirectory action="list" directory="c:\coldfusion8\mail\spool\" name="spool" sort="datelastmodified">
<cfset restart = 0>
<cfif datediff('n', spool.datelastmodified, now()) gt 30>
<cfset restart = 1>
</cfif>
<cfif restart>
<cfset sFactory = CreateObject("java","coldfusion.server.ServiceFactory")>
<cfset MailSpoolService = sFactory.mailSpoolService>
<cfset MailSpoolService.stop()>
<cfset MailSpoolService.start()>
</cfif>
We have not tried to run this without using the queue, due to the large amount of mail we send
Regardless, have you tried turning off spooling? I've seen mail get sent at a rate of 500-600 messages in a half second, and that's on kind of a crappy server. With the standard page timeout at 60 seconds, that would be ~72,000 emails you could send before the page would time out. Are you sending more than 72,000 at a time?
An alternative I used before CFMail was this fast was to build a custom spooler. Instead of sending the emails on the fly, save them to a database table. Then setup a scheduled job to send a few hundred of the messages and reschedule itself for a few minutes later, until the table is empty.
We scheduled the job to run once a day; and it can re-schedule itself to run again in a couple of minutes if the table isn't empty. Never had a problem with it.
Have you tried just bypassing the queue altogether? (In CF Admin, under Mail Spool settings, uncheck "Spool mail messages for delivery.")
I have the same problem sometimes and it isn't due to a zero byte file though that problem did crop up in the past. It seems like one or two files (the oldest ones in the folder) will keep the queue from processing. What I do is move all of the messages to a holding folder, restart the mail queue and copy the messages back in a chunk at a time in reverse chronological order, wait for them to go out and move some more over. The messages which were holding up the queue are put in a separate folder to be examined latter.
You can probably programmatically do this by stopping the queue, moving the oldest file to another folder, then start the mail queue and see if sending begins successfully by checking folder file counts and dates. If removing the oldest file doesn't work, repeat the previous process until all of the offending mail files are moved and sending continues successfully.
I hope the helps.
We have actually an identical setup, 32bit CF8 on Win2K3.
We employed Ben's solution about a year ago, and that certain has helped auto re-queue emails that get stuck.
However recently for no particular reason one of our 7 web servers decided to get into this state with every email attempt.
An exception occurred when setting up mail server parameters.
This exception was caused by:
coldfusion.mail.MailSessionException:
An exception occurred when setting up mail server
parameters..
Each of our web servers are identical clones of each other, so why it was only happening to that one is bizarre.
Another item to note is that we had a script which reboot the machine in the middle of the night due to JRUN's memory management issues. The act of rebooting seemed to initiate the problem. A subsequent restarting of the CF service would then clear it, and the machine would be fine until it rebooted again.
We found that the problem is related to the McAfee virus scanner, after updating it to exclude the c:\ColdFusion8 directory, the problem went away.
Hope that helps.
There is a bug in Ben Doom's code. Thank you anyway ben, the code is great, and we use it now on one of our servers with CF8 installed, but:
if directory (\spool) is empty, the code fails (error: Date value passed to date function DateDiff is unspecified or invalid.) That's because if the query object spool is empty (spool.recordcount EQ 0), the datediff function produces an error.
we used this now:
<!--- check if request for this page is local to prevent "webusers" to request this page over and over, only localhost (server) can get it e.g. by cf scheduled tasks--->
<cfsetting requesttimeout="30000">
<cfset who = CGI.SERVER_NAME>
<cfif find("localhost",who) LT 1>
security restriction, access denied.
<cfabort>
</cfif>
<!--- get spool directory info --->
<cfdirectory action="list" directory="C:\JRun4\servers\cfusion\cfusion-ear\cfusion-war\WEB-INF\cfusion\Mail\Spool\" name="spool" sort="datelastmodified">
<cfset restart = 0>
<cfif spool.recordcount GT 0><!--- content there? --->
<cfif datediff('n', spool.datelastmodified, now()) gt 120>
<cfset restart = 1>
</cfif>
</cfif>
<cfif restart><!--- restart --->
<cfsavecontent variable="liste">
<cfdump var="#list#">
</cfsavecontent>
<!--- info --->
<cfmail to="x#y.com" subject="cfmailqueue restarted by daemon" server="xxx" port="25" from="xxxx" username="xxxx" password="xxx" replyto="xxxx">
1/2 action: ...try to restart. Send another mail if succeeded!
#now()#
Mails:
#liste#
</cfmail>
<cfset sFactory = CreateObject("java","coldfusion.server.ServiceFactory")>
<cfset MailSpoolService = sFactory.mailSpoolService>
<cfset MailSpoolService.stop()>
<cfset MailSpoolService.start()>
<!--- info --->
<cfmail to="x#y.com" subject="cfmailqueue restarted by daemon" server="xxx" port="25" from="xxxx" username="xxxx" password="xxx" replyto="xxxx">
2/2 action: ...succeeded!
#now()#
</cfmail>
</cfif>
There is/was an issue with the mail spooler and messages with attachments in CFMX 8 that was fixed with one of the Hotfixes. Version 8.0.1, at least, should have had that fixed.