Catching requesttimeout in ColdFusion templates - coldfusion

I have a ColdFusion template, which will be called via ajax.
The template has timeout of seconds like:
<cfsetting showdebugoutput="true" requesttimeout="2" />
But if the timeout occurs, I get no error message back. Is there a way to catch the timeout and respond properly via Ajax?

I get no error message back
Do you get anything back? Your response should still contain the text ColdFusion produces. Have you used Chrome, or fire bug or any browser with web tools that allow you to see the response to see if you're just getting back something you can't use? Are you using anything with a success/fail callback function that may be suppressing the failure on the client side? If the below suggestion doesn't help, I'd post your JS and re-tag your question.
That being said: any time you do anything after the request timeout has expired you'll want to extend your timeout. onError and try/catch only have a few MS after the timeout to react to the error so sending messages or logging errors will also fail. If you were trying to send an email or write to a file, you're CF error message would then say your cfmail or cffile action timed out which it did (technically) but it isn't what caused the initial error.
You can simply reset the requestTimeout to something a little bigger if you know what the timeout is already.
<cfsetting requesttimeout="2">
<cftry>
<!--- some stuff that takes more than 2 seconds --->
<cfcatch type = "any">
<cfsetting requesttimeout="5">
<!--- logging / error handling for timeout --->
<!--- NOTE!! This does not add 5 seconds, it adds 3. --->
<!--- The value of requestTimeout is the total time of the timeout. --->
</cfcatch>
</cftry>
Or you can add time if you don't know the current timeout value.
<cftry>
<!--- some stuff that takes more than your timeout --->
<cfcatch type = "any">
<!--- You must first create your object to hold the requestMonitor. --->
<cfset monitor = createObject("java", "coldfusion.runtime.RequestMonitor") />
<!--- Then you need to reset your request timeout --->
<!--- add 5 seconds to the timeout --->
<cfsetting requesttimeout=monitor.getRequestTimeout()+5>
<!--- logging / error handling for timeout --->
</cfcatch>
</cftry>
You do not have to do this in a try/catch block either, you can include this in your onError event handler if you have one defined in your application.cfc.

If the ColdFusion template is in a folder for which there is an Application.cfc file, you might be able to do something with the onError function.

You should wrap your entire ColdFusion template that is being called by AJAX in a cftry block. That way if any ColdFusion exception occurs you can handle it and return whatever message you want to the client.
<cftry>
<!--- all of your ColdFusion template code here --->
<cfcatch type="Any">
<!--- return whatever you want here --->
<div>An error has occurred.</div>
<!--- remember that you have the cfcatch structure available to you --->
<!--- which contains the specifics of the error that was thrown --->
</cfcatch>
</cftry>
On the client side, where the AJAX call is being made, you can handle any http connection related errors that might occur (failed connection, timeout, etc.). Your AJAX call will have an error method or some such. I highly recommend using jQuery for this. jQuery AJAX API
You did not give any specific information in your post. If you have a problem it always helpful to actually share the code you are having trouble with. Then the people on StackOverflow can be of more help.

Related

Coldfusion cfmail with callback function

I'm using cfmail tag to send out emails to the user. Additional thing I need to fulfill is to delete the records after sending them to the users. Is there any solution available to observe the cfmail task is whether completed or not. For example like a callback to indicate that the task was done.
With emails there are no guarantees that the email has been delivered.
If the cfmail tag executed without error there will be a record in the cfml spool directory. After the server hands the mail over to your SMTP server coldfusion removes the email from the spool directory.
NOTE: If your server is fast you will never see the mail in the spool folder.
You could try and build a solution that inspects the mail logs, but even that gives you no guarantee that the email has been delivered.
In most cases knowing that cfmail executed is enough.
<cfquery name="emailStuff">
SELECT * FROM mytable
</cfquery>
<cfloop query="emailStuff">
<cfmail>
cfmail contents/properties
</cfmail>
<cfquery>
DELETE FROM mytable WHERE ID=emailStuff.ID
</cfquery>
</cfloop>
Not sure if the above is what you're looking for. But this is a rough example of some code that will delete your DB entry after the mail has been sent.
Also cfmail has properties for failto and debug.
If an email fails it will send the failure email to whomever you specify in failto, or you can use debug to log failed emails.
see: cfmail docs
UPDATE: You could also move the delete query to outside the loop so that it only needs to delete from the database in one swift motion.
<cfloop query="emailStuff">
<cfmail>
cfmail contents/properties
</cfmail>
</cfloop>
<cfquery>
DELETE FROM mytable
WHERE ID IN (<cfqueryparam list="yes" value="#emailStuff.ID#" />)
</cfquery>

Is there a way Coldfusion can send all errors to a specific email?

I have:
Server Details
Server Product ColdFusion
Version 9,0,1,274733
Edition Standard
Operating System Windows Server 2008
OS Version 6.0
Adobe Driver Version 4.0 (Build 0005)
Is it possible that I can receive all the errors that happen on coldfusion to a specific email?
If you don't want to add a cferror to every page you can add a onError method to your application.cfc this function will be called whenever any page has an error.
<cffunction name="onError">
<!--- The onError method gets two arguments:
An exception structure, which is identical to a cfcatch variable.
The name of the Application.cfc method, if any, in which the error
happened. --->
<cfargument name="Except" required="true"/>
<cfargument type="String" name = "EventName" required="true"/>
error handling goes here
</cffunction>
I also saw you had a question where you were worried about the mail server not working. If you are worried that you will not be able to receive emails about your errors you can log them to a file.
<!--- Log all errors in an application-specific log file. --->
<cflog file="filename" type="error" text="Event Name: #Eventname#" >
<cflog file="filename" type="error" text="Message: #except.message#">
Check out the cferror tag. It is exactly what you need.
You can put cferror in the Application.cfm file, if you are not using Application.cfc, and it will work on every page.
<cferror type="exception"
template="/error.cfm"
mailto="your#email.com"
exception="any">
This is the recommended way to email notification of errors pre CFMX7. It still works in CFMX7 and after but best practice suggests the use the onError() method of Application.cfc
wikidocs.adobe.com/wiki/display/coldfusionen/onError

COM.Allaire.ColdFusion.HTTPFailure

I'm working on a web app that is ran nightly to retrieve a large XML file from another server. We're using ColdFusion MX7. We run a CFHTTP GET with username, pass, and url. Then we write the field with a cffileaction write to our temp location. So that it can be parsed and sorted into a database. There are a few CFHTTP calls on the page cut one of them is failing. In the CFCatch I have the system email me the catch type and the message and I'm getting this.
COM.Allaire.ColdFusion.HTTPFailure
Connection Failure: Status code unavailable
This the call an write action as is (the credentials are right):
<cfhttp method="GET"
username="#uname#"
password="#pw#"
url="#url#"
resolveurl="yes"
throwonerror="yes">
</cfhttp>
<cffile action="write" file="#getdirectoryfrompath(GetCurrentTemplatePath())#\XML_FileName.xml" output="#cfhttp.fileContent#">
Is anyone familiar with his error?
As it turns out we were getting the Cert from the other groups 'test' server and then trying to using to get things from their production server. So Peter was right! If you run into this problem check out these links:
CFHTTP Over SSL
http://www.houseoffusion.com/groups/cf-talk/thread.cfm/threadid:48687

Coldfusion gateway, problem with application.cfc OnRequestStart

My application.cfc uses the OnRequestStart to check users are logged in
<cfif not isDefined("session.auth.isLoggedIn")>
<cfinclude template="loginForm.cfm">
<cfabort>
</cfif>
and this is mangling my attempts to use a gateway service which errors out with
Error invoking CFC for gateway watchInboundFiles: null {GATEWAYTYPE={FileWatcher},ORIGINATORID={},CFCMETHOD={onDelete},DATA={{FILENAME={C:\temp\New Text Document.txt},TYPE={DELETE}}},CFCPATH={F:\ColdFusion9\wwwroot\watch_dir.cfc},GATEWAYID={watchInboundFiles}}.
If I comment out the OnRequestSTart method the gateway works as expected.
Someone else ran into this before here and a solution is apparently to
add a new application.cfc which
extended my original but overrode the
onRequestStart() - which worked
perfectly.
So how do I do that please?
To answer your question:
Your new Application.cfc will live in another directory but extend your original:
<cfcomponent extends="path.to.my.original.Application">
<cffunction name="onRequestStart">
<!--- No login code here --->
</cffunction>
</cfcomponent>
All other functions are available as usual.
Hoep that helps! More info here.
You could also add something to the application.cfc to see if the call is coming from the gateway. If so then skip the if block.

restart application without restarting server?

Is there a way to restart a ColdFusion application without restarting the entire server?
There are two ColdFusion applications running on a server and I only want to restart one of them.
If you are using Application.cfc, you can update it so that you can force a call to onApplicationStart() if something specific is passed in the url, or something similar. Simply place a check for that magic token in onRequestStart(), and call onApplicationStart() if it is.
If you are not, you can try #Marcos's suggestion. I'm not sure what ramifications that may have in your application. What I would suggest is actually renaming your application, so it starts as a new app.
If you're on CF9, run ApplicationStop() https://cfdocs.org/applicationstop
Here you go, my CF7/8 version of CF9's ApplicationStop. I believe this is thread safe, noting Sean's comment.
<cffunction name="ApplicationStop" returntype="boolean" output="false">
<cfif IsDefined('application')>
<cftry>
<!--- This is just in case there's no app scope but variables.application --->
<cfset CreateObject('java', 'coldfusion.runtime.ApplicationScopeTracker').cleanUp(application) />
<cfreturn true />
<cfcatch type="any"></cfcatch>
</cftry>
</cfif>
<cfreturn false />
</cffunction>
As mentioned by Henry, he's my blog post on the subject:
http://misterdai.wordpress.com/2010/06/14/cf-flag-application-to-run-onapplicationstart-part-2/
A less invasive way of ending your app is to temporarily set the ApplicationTimeout to something very short.
Here is an example from an application.cfc file where the app is set to timeout in 10 seconds, which is plenty short for making a change and then checking back:
<cfcomponent displayname="Application">
<cfscript>
this.name = "myAppName";
this.setclientcookies="yes";
this.sessionmanagement="yes";
this.sessiontimeout= CreateTimeSpan(0,0,60,0);
this.applicationTimeout= CreateTimeSpan(0,0,0,10);
</cfscript>
...
</cfcomponent>
You might need to limit the session, too. See this article by Ben Nadel for an in-depth look at Application and Session timeouts.
If you are using application.cfc, stick this at the top of your onRequestStart function:
<!--- RESET APP? --->
<cfif isdefined("url.reinit")>
<cfset OnApplicationStart()>
<cfset OnSessionStart()>
</cfif>
Then you can pass a url var to any cfm and the app will reset.
<cfset structClear(application) />
I usually put a reference to each user's session into a struct in my Application scope to monitor what's going on in the app. Maybe doing something similar in the Server scope could help here. Try:
<cfset server.runningApplications["myApp"] = Application />
Then you'd have a reference to the actual Application object outside the scope of that application. You could try all manner of destructive things to get rid of it. Try this at your own risk!!! And do it on a dev server before you do it on your production box. ;)
Use cfinvoke.
<cfinvoke method="onApplicationEnd" component="Application">
<cfinvokeargument name="ApplicationScope" value="#application#" />
</cfinvoke>