Ask a Jedi: Refreshing Application Variables

A reader asks,

When you've used OnApplicationStart to store application variables how do you refresh it?

Simple - I use a URL variable. Inside my onRequestStart, I'll have something like this:

<cfif structKeyExists(url, "refreshmebabyonemoretime")> <cfset onApplicationStart()> </cfif>

A few notes. The name of the URL variable is completely arbitrary. You probably want something people can't guess, but it is up to you to decide how anal/secure you want to be.

Also - remember that when ColdFusion runs onApplicationStart by itself, it does so in a single threaded manner. When you run it, it isn't single threaded. But if you are just setting a bunch of application variables, it probably will not matter to you.

p.s. So hey, did you notice I used structKeyExists instead of isDefined? I'm slowly coming around to it. ;)

Archived Comments

Comment 1 by Brian Rinaldi posted on 11/28/2005 at 8:58 PM

Excuse my ignorance on the topic, but what is the benefit of using StructKeyExists instead of isDefined? Faster or just better form?

Comment 2 by Brian Kotek posted on 11/28/2005 at 10:33 PM

isDefined() can lead to unexpected results becuase it will look through a number of scopes trying to find the specified variable. So isDefined() may return true when you expect it to return false, and vice-versa, when a variable with the same name exists in another scope.

Comment 3 by Justice posted on 11/28/2005 at 10:51 PM

Yea, ever since I got grief about using isDefined in my guess a number game, all my code is strictly structKeyExists now! =)

Comment 4 by Fernando Lopez posted on 11/29/2005 at 12:00 AM

what's the difference of using the StructKeyExists and a line like this?

<cfif IsDefined("url.refreshmebabyonemoretime")>

I could understand that having something similar to

<cfif IsDefined("refreshmebabyonemoretime")>
would potentially give you unexpected results.
but the first option works for me.
any pros or cons?

Comment 5 by Seth Petry-Johnson posted on 11/29/2005 at 12:15 AM

> isDefined() can lead to unexpected results becuase it
> will look through a number of scopes trying to find the
> specified variable. So isDefined() may return true when
> you expect it to return false, and vice-versa, when a
> variable with the same name exists in another scope.

That make sense if you don't specify a scope, but why is IsDefined("url.SomeVar") different from StructKeyExists(url, "SomeVar")? Is there a performance benefit of one versus the other?

IMHO IsDefined("url.SomeVar") is preferable because it doesn't couple the logic to a specific CF storage mechanism. In other words, if the folks at Macromedia lose their minds and decide that CF 8 will no longer use a struct to model the URL scope, code using IsDefined will continue to work. (Yes, I know this example is reaching, but for me its enough to stick with IsDefined() unless someone can show me a compelling reason otherwise)

Just wondering,
Seth

Comment 6 by Steve Bryant posted on 11/29/2005 at 1:02 AM

The other benefit is performance. StructKeyExists() performs faster (at least in CFMX) than does isDefined(). I don't think performance gains of this kind are worth much extra effort, but then using StructKeyExists() doesn't take much extra effort.

Comment 7 by tony of the weeg clan posted on 11/29/2005 at 1:40 AM

if it performs better in that it views a null value as not defined, then im sold. until then its

isDefined("") and len()

for me.

tw

Comment 8 by Justice posted on 11/29/2005 at 2:16 AM

I would just use structKeyExists(url, "blah") AND url.blah neq '' for that, does the same thing.

Comment 9 by Rob Gonda posted on 11/29/2005 at 10:15 AM

StructKeyExists will find elements that isDefined will not. A specific example is an array of structures.

e.g.
StructKeyExists(sessionOnlineArray[i], 'init') inside a loop will return true or false, but isDefined will break and throw a CF error.

So altough I mostly use isDefined, StructKeyExists has more versatility; furthermore, if it has performance advantages, there should be no questions about it.

Comment 10 by tony of the weeg clan posted on 11/29/2005 at 10:26 AM

guess its time to explore it.
talk about paradigm shift. damn, i think i dream about isDefined() and len() in my cfif statements :)

Comment 11 by Peter Boughton posted on 11/29/2005 at 2:48 PM

Are people saying that url.blah neq '' is better than len(url.blah), or am I reading things wrongly?

Comment 12 by Steve Bryant posted on 11/29/2005 at 4:57 PM

One person said that. I prefer Len().

Comment 13 by Rob Gonda posted on 11/29/2005 at 7:28 PM

Len() is faster.

Comment 14 by Peter Boughton posted on 11/29/2005 at 8:02 PM

I could have sworn there was more than one person earlier.
Oh well.

Anyhow, just to see if there was a significant performance difference I did a quick test - looped through each ten thousand times. The mean average result of the first five runs was 269ms and 281.2ms (for Len and EQ '' respectively), and the all fifteen runs it was 117.7ms for Len() and 125ms for EQ '', with both having a median of 47ms.

So, using Len() is prettier and might save a whole ten milliseconds! :)

Comment 15 by Andrew posted on 12/23/2005 at 5:06 AM

I am kind of a newbie when it comes to differently scoped variables in ColdFusion. I am quickly getting up to speed. I have seen this construct utilized in many examples, but none have shown how to load said variable into the structKey. How is that done? I've tried loading the variable in the pages address as part of a query string with no luck. I am sure there is something very basic that I am missing here.

Comment 16 by Raymond Camden posted on 12/23/2005 at 8:12 PM

I'm not quite sure what you mean Andrew. "load said variable into structKey"? Do you mean set a variable in a struct? If so it is rather simple, cfset foo.moo = "value", or cfset foo["moo"] = "value". You should be able to read up on structs in the cf docs.

Comment 17 by Andrew posted on 12/23/2005 at 9:02 PM

I was referring to the URL struct specifically. I do understand how to access a struct programatically, but specifically the URL struct is most often used in the context of your example. Ben Forta uses a similar example in his chapter on Advanced ColdFusion Components in CFMX7 Application Development. I started thinking about the problem some more and realized how the URL struct works - each parameter of the query string makes up the entire URL struct. With that in mind I tested with a link formed somewhat like this: http://www.foo.org/test.cfm.... Worked like a charm. Thanks for the good article and giving me a place to use as a sounding board.

Comment 18 by Raymond Camden posted on 12/23/2005 at 10:45 PM

Ah - yes - that's just a feature built into CF. It will auto-break the query string apart into a struct. I remember the old days of parsing query strings in PerlCGI. :)

Comment 19 by Dave Shuck posted on 1/3/2006 at 1:40 AM

Have you ever seen this method fail to restart the application? I have tried Ray's method above and tried another thread-safe version I say Barney suggest to someone on a list somewhere (don't recall at the moment), and I can't seem to make it work. Just for testing I outputted text before and after the call to onApplicationStart() which is being displayed. I even outputted some text inside the onApplicationStart method, which also displayed, but when I dump the application scope afterwards, I still have data that from before the refresh. Any ideas?

~Dave

Comment 20 by Raymond Camden posted on 1/3/2006 at 7:22 AM

What do you mean it doesn't work? If you add a cflog statement to onApplicationStart, do you see a log event if you call it with my method?

Comment 21 by Dave Shuck posted on 1/3/2006 at 7:43 AM

Ray,

This is my onApplicationStart:
<cffunction name="OnApplicationStart">
<cflog file="inetap-mii" text="The application was started at #now()#." type="information" />
</cffunction>

When I use the method you list, I can clearly see it make an entry into inetap-mii.log. However...

Before I ran this, created a structure in the application scope. After running the reload and seeing the log entry made, I can <cfdump var=#application# /> and still see the structure that I had previously added to the application scope (and I confirmed this wasn't client side caching). My understanding is that the Application scope would be fresh at this point as if I was running the application for the first time. Am I just misunderstanding what onApplicationStart can do for me? Thanks.

~Dave

Comment 22 by Raymond Camden posted on 1/3/2006 at 7:53 AM

If should refresh - however - why not just restart CF? If you are making changes to the application .cfc file, it may be best.

Comment 23 by Dave Shuck posted on 1/3/2006 at 7:56 AM

Well at this point it has just become a matter of principle! :) Restarting works. I was just trying to figure out why this wasn't doing the trick. Thanks.

Comment 24 by Raymond Camden posted on 1/3/2006 at 8:02 AM

Heh, I hear ya. I just tend to go to a restart if CF is being "wierd." And it sounds like it may be for you.