Quick Application.cfc Review

A user sent in a request for me to look over some code he would like to use for his Application.cfc file. (As an aside, don't forget my online Application.cfc template you can use.) The template looked nice but had one main issue that I noticed. Since the user got the template from someone else, I won't post the whole thing as it isn't my code, but I will demonstrate the problem I saw.

First is the onSessionStart:

<cffunction name="onSessionStart" output="false"> <cfscript> session.started = now(); </cfscript>

<cflock scope="application" timeout="5" type="Exclusive"> <cfset application.sessions = application.sessions + 1> </cflock> </cffunction>

Notice that he is keeping count of the sessions, a topic I covered last week. Most importantly though - notice his lock. He is using a scope based lock to ensure his update of the application variable is single threaded. Now lets move on to the onSessionEnd method:

<cffunction name="onSessionEnd" output="false"> <cfargument name = "sessionScope" required=true/> <cfargument name = "applicationScope" required=true/> <cfset var sessionLength = TimeFormat(Now() - sessionScope.started, "H:mm:ss")>

<cflock name="AppLock" timeout="5" type="Exclusive"> <cfset arguments.applicationScope.sessions = arguments.applicationScope.sessions - 1> </cflock> </cffunction>

(Forgive the bad formatting - this came in via email.) Notice the problem? Try to figure it out before reading on.

He correctly uses a lock again to update the session count. But he can't use a scope lock since the application scope isn't available directly in onSessionEnd. That's why he has to use the application scope passed in via arguments.

So the problem then is that in one case he has a scope based lock and in another case he has a named based lock. He needs to use one or the other. Since he can't use a scope lock in onSessionEnd he should use the named based lock only.

p.s. A few other small things that I'll point out that are minor but bug me: I don't like using cfscript as he did here, just for one line of code. He also forgot the arguments prefix for sessionScope in onSessionEnd. I tend to be anal about using the arguments prefix in my methods.

Archived Comments

Comment 1 by Jay McConathy posted on 3/21/2007 at 5:05 PM

Since I have never setup an appplication.cfc nd have usually used application.cfm I know I am behind the curve.. however just to make sure, and I am sure this is a stoopid question, I can just rename the application.cfm files to application.cfc and make the appropriate code changes for it to work correctly?

Comment 2 by Phillip Senn posted on 3/21/2007 at 5:12 PM

Ray,

Your app.cfc reference has
<cfset this.scriptProtect = false>

Shouldn't it be the following?
<cfset this.scriptProtect = "all">

Comment 3 by Raymond Camden posted on 3/21/2007 at 5:22 PM

PS: No. I prefer to write my own security. Plus I find scriptProtect tends to interfere at times, like on a blog if you try to post code as the author, it will block it. It _is_ a nice feature, I just don't use it myself.

Comment 4 by gemma posted on 3/21/2007 at 5:27 PM

great website and good idea! However, you spelt my hometown wrong...its spelt worcester park. Not that it matters but thought you should know

Comment 5 by Raymond Camden posted on 3/21/2007 at 5:42 PM

@Jay - I wouldn't just rename it. A CFC is quite different from an CFM file. You need to reorganize stuff. I'm pretty darn sure I did a blog entry on this.

Hmm, I can't find it.

I can maybe write a new one on it. Do you have a good, and not too complex App.cfm you could share?

Comment 6 by Tom Mollerus posted on 3/21/2007 at 5:51 PM

Ray, why is it necessary to use only one kind of lock, named or scoped, across the whole Application.cfc?

Comment 7 by Raymond Camden posted on 3/21/2007 at 6:10 PM

Tom:

2 issues.

1) It is important to use the same type of lock, or it is useless.

2) onSessionEnd can't use the scope lock, it can only use the named lock.

Comment 8 by Jay McConathy posted on 3/21/2007 at 6:34 PM

I have a very simple newbie one ..

here it is..

<CFSETTING ENABLECFOUTPUTONLY="Yes">
<CFAPPLICATION NAME="QAX"
CLIENTMANAGEMENT="Yes"
SESSIONMANAGEMENT="Yes"
SETCLIENTCOOKIES="Yes"
SESSIONTIMEOUT="#CreateTimeSpan(0, 8, 0, 0)#"
APPLICATIONTIMEOUT="#CreateTimeSpan(0, 8, 0, 0)#"
CLIENTSTORAGE="Registry">
<CFERROR type="request" template="app_error.cfm" mailto="jay_mcconathy@txeb.uscourts.gov">

<!--- Do I need to create my app var? --->
<cfset needInit = false>
<cflock scope="application" type="readOnly" timeout="30">
<cfif not structKeyExists(application,"sessions")>
<cfset needInit = true>
</cfif>
</cflock>

<!--- Yes, I do need to make it. --->
<cfif needInit>
<cflock scope="application" type="exclusive" timeout="30">
<cfif not structKeyExists(application,"sessions")>
<cfset application.sessions = structNew()>
</cfif>
</cflock>
</cfif>

<!--- Store my last hit. --->
<cfset application.sessions[session.urltoken] = now()>

<CFSETTING ENABLECFOUTPUTONLY="No">

Comment 9 by Jay McConathy posted on 3/21/2007 at 6:35 PM

I have not seen a blog entry on it which is why I am asking..

Comment 10 by Paul posted on 3/21/2007 at 11:03 PM

Do you have to var scope the lock name like you would a query name?

Comment 11 by Raymond Camden posted on 3/22/2007 at 12:21 AM

As far as I know, no.

Comment 12 by Jean-Michel Rottiers posted on 3/22/2007 at 2:02 PM

mmm Ray & Jay there's this entry in the coldfusion cookbook ;-p

http://www.coldfusioncookbo...

Comment 13 by Tom Mollerus posted on 3/22/2007 at 5:54 PM

Ray,

I think I've realized why I was confused, and I'm wondering if you can confirm: the problem wasn't that the user was merely using two different kinds of locks in Application.cfc; the problem was that the user had two different kinds of locks protecting the same scope, which would render them less effective, right?

Comment 14 by Raymond Camden posted on 3/22/2007 at 8:00 PM

It doesn't render it less effective. It renders it UNeffective. :)

Comment 15 by Matthew Zimmer posted on 4/10/2008 at 7:12 PM

Great post Ray and thank you for confirming my suspicion on this. I'm trying to clean up another developer's Application.cfc logic and I came across this very scenario which threw up a red flag.

One thing, though:

As I read the sentence "But he can't use a named lock since the application scope isn't available directly in onSessionEnd" I was a bit confused. Since nobody has commented on it yet I suppose most understood what Ray was trying to say, though, I feel like posting a comment to help out the noobies (not to correct Ray as the paragraph immediately following this sentence already does that for us), the sentence should read:

"But he can't use a [scope based lock] since the application scope isn't available directly in onSessionEnd"

When in doubt, check Ray's blog!

^ Write that down :)

Comment 16 by Raymond Camden posted on 4/10/2008 at 7:15 PM

Good catch there Matt. I'll edit the post.

Comment 17 by Kate posted on 10/7/2009 at 7:21 PM

When switching from Application.cfm to Application.cfc and adding error handling my load time has increased dramatically. A page on the server using .cfm loads in about half a second, whereas the .cfc's server page takes over 9 seconds to load. Is this normal?

Comment 18 by Raymond Camden posted on 10/7/2009 at 7:27 PM

Nope. Can you show us your code? Use Pastebin please.

Comment 19 by Kate posted on 10/7/2009 at 7:45 PM
Comment 20 by Raymond Camden posted on 10/7/2009 at 7:56 PM

There is a lot wrong with this file - but none that immediately imply a slowdown. Comments from top to bottom.

Lines 15-20. If you use J2EE Sesions (CF Admin setting) you can get rid of those lines.

Line 22 doesn't make sense. This should either be an Application variable.

Lines 24 is an include. What is the purpose of it being there? It will run on every request. If you want that - use it within onRequestStart.

Lines 25-33 should most likely be in onSessionStart. No - lines 25-27 shoul dbe. Lines 29-33 should probably be in onRequestStart.

Think of it like this - if you want something to run on every request, you really want to use the onRequestStart method. If you want to define some session variables then you to use onSessionStart.

You can also consider wrapping your code blocks with <cftimer> to determine the exact portion that is slowing things down.

Comment 21 by Kate Maher posted on 10/25/2009 at 9:33 PM

Thanks Ray! I made those changes. The timing seemed to calm down a bit the more pages I ran. I'm not sure why that'd happen, but it did. cftimer just showed close to 0ms runs, so maybe it was something else completely. Thanks for all your help!