Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at Scotch On The Rocks (SOTR) 2011 (Edinburgh) with:

ColdFusion 8 Per-Application Settings Get Partially Cached (And There's Nothing You Can Do About It)

Posted by Ben Nadel
Tags: ColdFusion

NOTE: The code in this post can be very misleading if you don't read the explanations that go with it!!

When I was playing around with some ColdFusion custom tags, I stumbled upon some interesting behavior in ColdFusion 8's per-application settings. From what I can see and re-create, the CustomTagPaths property is cached for the life of the application; but, the Mappings property, on the other hand, is not cached at all and needs to be defined in every page request that uses them. To demonstrate this, I have put together a short demo that uses the CustomTagPaths property to execute a custom tag and the Mappings property to create and utilize a ColdFusion component:

 
 
 
 
 
 
 
 
 
 

As you can see from the video, THIS.CustomTagPaths can be set once for the application and then never set again; THIS.Mappings, on the other hand, needs to be set on every page request. Now, I've seen people in the blogosphere and on the mailing complain that they are getting some intermittent errors with ColdFusion 8's per application settings and I wonder if it has something to do with this partial caching behavior?

To work in alignment with this caching strategy, I considered rearchitecting the way in which I define my per-application settings. In particular, I thought that I should probably only set the CustomTagPaths property once in the OnApplicationStart() event method and the Mappings property in the pseudo constructor such that it will be set on every page request:

  • <cfcomponent
  • output="false"
  • hint="I define application settings and event handlers.">
  •  
  • <!--- Define application settings. --->
  • <cfset THIS.Name = "TagPathDemo" />
  • <cfset THIS.ApplicationTimeout = CreateTimeSpan( 0, 0, 0, 15 ) />
  •  
  • <!---
  • Define custom mappings. These need to be set on EVERY
  • page request. Put in psuedo constructor so all events
  • can leverage them.
  • --->
  • <cfset THIS.Mappings[ "/com" ] = (
  • GetDirectoryFromPath( GetCurrentTemplatePath() ) &
  • "components\"
  • ) />
  •  
  •  
  • <cffunction
  • name="OnApplicationStart"
  • access="public"
  • returntype="boolean"
  • output="false"
  • hint="I fire when an application needs to be initialized.">
  •  
  • <!---
  • Define ColdFusion custom tag paths. Since these
  • values are cached, they only need to be set once
  • when the application is intialized.
  • --->
  • <cfset THIS.CustomTagPaths = (
  • GetDirectoryFromPath( GetCurrentTemplatePath() ) &
  • "tags\"
  • ) />
  •  
  • <!--- Return true so page will run. --->
  • <cfreturn true />
  • </cffunction>
  •  
  • </cfcomponent>

This makes sense based on the behavior, but unfortunately does NOT work. When I run the page with this Application.cfc configuration, I get the following ColdFusion error:

Cannot find CFML template for custom tag helloworld.

So, it seems that the CustomTagPaths property gets cached, but the behavior is not quite so straightforward. So what next? I tried moving it to the OnRequestStart() event method. Also no luck - same error. It appears that the per-application settings need to be set outside of any of the application event handlers.

At this point, we've run out of elegant solutions - if we don't define the CustomTagPaths in the pseudo constructor, they don't work; however, if we do define them, we set them unnecessarily; and finally, if we don't set them, we can't really check for their existence since they are not available in the THIS scope when not set explicitly.

The only thing I could think of was trying to execute a custom tag, catching any errors, and then defining the custom tag paths if necessary:

  • <cfcomponent
  • output="true"
  • hint="I define application settings and event handlers.">
  •  
  • <!--- Define application settings. --->
  • <cfset THIS.Name = "TagPathDemo" />
  • <cfset THIS.ApplicationTimeout = CreateTimeSpan( 0, 0, 0, 15 ) />
  •  
  • <!---
  • Define custom mappings. These need to be set on EVERY
  • page request. Put in psuedo constructor so all events
  • can leverage them.
  • --->
  • <cfset THIS.Mappings[ "/com" ] = (
  • GetDirectoryFromPath( GetCurrentTemplatePath() ) &
  • "components\"
  • ) />
  •  
  •  
  • <!---
  • Try to execute the tag check custom tag. If this fails
  • (throws an exception), then we need to initialize the
  • custom tag paths. If it DOES work, then the paths have
  • been initialized and cached.
  • --->
  • <cftry>
  • <!--- This tag doesn't do anything. --->
  • <cf_checktagpaths />
  •  
  • <!--- Tag failed - Define custom tag paths. --->
  • <cfcatch>
  •  
  • <cfset THIS.CustomTagPaths = (
  • GetDirectoryFromPath( GetCurrentTemplatePath() ) &
  • "tags\"
  • ) />
  •  
  • </cfcatch>
  • </cftry>
  •  
  • </cfcomponent>

As you can see, I am defining the CustomTagPaths property only if the custom tag "CheckTagPaths.cfm" failed to execute.

Not only is this very sloppy looking, it also does NOT work; the CheckTagPaths.cfm custom tag throws an exception on every request. From further experimentation, it seems that you cannot utilize the ColdFusion 8 per-application settings within the pseudo constructor itself - you have to wait until one of the application event handlers.

In the end, it appears that all of this exploration is for naught - the CustomTagPaths get cached for the life of the application, but there is no way for you to leverage that fact that I can find.

UPDATE: Just a quick update based on the comments that Ray Camden mentioned below. I had no idea that ColdFusion has cached tag references; however, after some quick testing, I have verified that it is not the custom tag itself that is being cached in my experimentation, but rather the directory:

 
 
 
 
 
 
 
 
 
 



Reader Comments

Ben, I skimmed this. I did NOT read it closely. But are you forgetting that CF remembers the location of a custom tag? If you call cf_foo, and it finds it in path N, cf will never look for cf_foo elsewhere. This is less a App.cfc bug and just a custom tag behavior that has not changed since CF5.

Again, forgive me if this is not the issue.

Reply to this Comment

Yep. Super old behavior. Maybe even back to when CTs were added (CF3 I think).

Of course, cfmodule doesn't have this problem.

Reply to this Comment

@Ray,

I just tested this and it is not the case - even when I put in another, not previously used tag, the mapping still exists.

Reply to this Comment

Ah ok. Well, if you ARE changing the CT path during dev, it is still important to remember. Once you run cf_foo and CF finds it, you are screwed.

Reply to this Comment

Have you actually seen errors with per-application settings under load? I ask, because I too have heard of issues, but haven't actually seen them.

Reply to this Comment

Sidenote: I like the screencasting that you've been doing lately. It's much more approachable than a wall of code -- you're still getting the wall, but having it spoken and shown visually just works better for me, I guess.

Reply to this Comment

Angela and I have been dealing with this for quite some time. We ended up defining the CustomTagPaths outside any contructors, but then defining it again in the onRequestStart() to get around some race conditions we were experiencing.

I think the CustomTagPaths is definitely something that needs to be worked on for CF9.

Reply to this Comment

In your second demo, I didn't see that you commented out the custom tag path before running the second custom tag (helloworld3).

Reply to this Comment

@Rick,

Thanks man. I really like the video walk throughs. I am not sure where the right balance is between code / video because the screen size is so small. If I can find a nice way to record a larger video, but still have it fit inside my blog content, I might go that way as I think it would provide more value.

@Nathan,

I have not experienced this error myself; so it's hard to know what does or does not contribute to it exactly.

Reply to this Comment

@RickO: (Ben, forgive me for hijacking this a bit.) I've used Jing a few times, but never really got any good feedback on it. You think it is worthwhile using more often?

Reply to this Comment

@Ray,

No problem :) I love Jing, but I want to find a better way to record larger dimension videos yet still embed easily.

@Nathan,

No worries.

Reply to this Comment

Off-topic (regarding Jing): Aren't you just limited by what your machine can handle? I have Jing Pro and I can record any size I want even a thin 200x1000 video strip? There are limitations, but size isn't one of them.

Reply to this Comment

The video does have the option to go full screen and it looks fine. You have to hover over the video and you'll see a tiny bar at the bottom, it's too small to see the full screen button, but it's there.

Instructions:

1) Right click on the video and Zoom In
2) Drag the video to the left
3) Click the full screen mode
4) Righ click and zoom out a couple of times
5) You may have to reposition the screen

Reply to this Comment

Sorry, I just tried a simpler method:

1) Right click and choose show all
2) Click the full screen button

That's it!

Reply to this Comment

@Ben

This bit us recently with the mappings and how part of our platform worked.

All of our applications live in the same CF application and each has a section of the application scope. I had it defining an auto mapping for the root of each sub-application (which is outside the webroot) at the start of every request.

this.mappings["/" & listLast(getRootPath(),"\/")] = getRootPath()

I started seeing random errors about not being able to find certain components, but I couldn't duplicate it... until I decided to cross application load test.

We had also setup explicit mappings in the Admin for most applications from back when we were on CF7 and this had been masking the fact that the implicit root mapping sometimes would vanish! So only new apps that didn't have CF Admin mappings would fail.

So the moral of the story is that *every* request shares the same this.mappings, but it also has to be initialized at the start of *every* request with the *exact same values*. Otherwise requests that are currently running can have their mappings up and vanish in the middle because of a different request!! :/

Reply to this Comment

@Daniel Short,

We also ran into huge problems with the per-app customtagpaths and what seemed like some race time trouble. I'd be interested in seeing the code you used to get around these issues.

Reply to this Comment

@Todd,

Yeah, that's true. I guess I'm just more worried about the embed code; I guess it's cause I never really thought about it. I could always record a large video and then just scale it down for the embed code :)

@Elliott,

What would be good would be to allow us to put the values in the OnApplicationStart() event handler. That way, we could keep them to a single setting.

Reply to this Comment

Just wanted to say that I loved the screen capture used in the post Ben. It's the first I've seen you use and actually came here to see how you were using Jing after we talked about it on Twitter.

It worked brilliantly in this example and engaged me a lot more than just reading the blog post.
I like how it really engages you to the viewer as well helping to get the content of the post across.

I don't think the screen size matters too much - at least not in this example. Where more width is needed the bigger screen cap with smaller embed code would do the trick nicely I'd think.
Nice to be able to play it embedded though where possible.

Interesting post by the way. Not something I was aware of and useful to know.

Reply to this Comment

A note here from our conversation on this - if you were to restart your server instance after you commented that out custom tag path I'd expect that template you executed to fail - and not find the CT path - (as the cache would no longer be available). Is that what you found - I'm assuming so?

Reply to this Comment

Very interesting detail regarding this topic, is How Ben forget to say that he has written this post AFTER I've send him an email regarding problems with application specific customtags mappings, on an application that is build using HTML frames that loads different coldfusion pages in each frame.

I've offer obviously a PROBLEM not a solution, but is sad to see how people can ommit some details.
I'm not need to be named here is not the idea, I've not ego problems.

IMHO instead of starting post saying " .. While I was playing...",
a better approach can be " I've received an email regarding problems with ...., then I've decided to play a little bit to ...' .

Regards

Reply to this Comment

@Francisco,

Here is the email that you sent me:

> I've have started using Application.cfc on CFMX 8 because I want to
> be able to set different customTagPaths for every application hosted on my CF
> server. I have found a problem because my app uses frames (and I can not
> rewritte app). Seems initalization of this.customTagPaths is corrupted, because
> app can not find custom tags after login page (has no frames) when entering main
> screen (has 3 frames). Any hint?

To which, I tried to write a blog post. Unfortunately, I couldn't turn your idea into anything which is why I then told you (CC'ing gualtiero.sappa and alessandro.lia):

Francisco, My blog post was a bust. Sorry.

The blog post I tried to write for you involving frames is completely unrelated and was not something that I could solve. This blog post (the one above) has nothing to do with your email; there is no reference to frames, no reference to login pages. The only thing that your email and my blog post have in common is that they work with custom tag paths... which is a big part of my Custom Tags presentation I've given months ago and will give again at CFUNITED. It is in the research for this presentation that I first discovered partial caching of custom tags.

I am sorry that you feel that I have somehow skipped over you or not acknowledged you; I hope that you see that on my blog, I give credit for things as often as possible - I love giving people credit for stuff. I am sorry if you were confused as to where this blog topic came from.

Reply to this Comment

@All,

I would like to apologize for my last comment - I definitely came off as very defensive (followed by offensive). I felt attacked and I should have followed up with @Francisco via email rather than publicly.

While my blog post is not related to the question he originally asked me, I believe our misunderstanding is due to a strong language barrier that skewed communication. I am sorry that I let me emotional side take over my response.

Reply to this Comment

@Ben: I wouldn't worry about it or lose sleep over it. The whole thought of this is just silly. You certainly don't have to defend your every post or where your muse strikes from.

Reply to this Comment

I am having a similar issue. I have specified a per-application customtags path in my application. For the most part it is working just fine, however, when custom tags are being used within CFC methods or scheduled tasks, I'm gettting an exception saying that it cannot find the custom tag. I noticed a bug fix in the latest CF8 hot fix (http://kb2.adobe.com/cps/511/cpsid_51180.html) is supposed to fix this issue, but after applying it, the same behaviour is occurring.

Does anyone have a solution for this? I don't want to rely on custom tag paths in the administrator. I want my applications to be self-contained.

Thanks.

Reply to this Comment

We ran into an issue where we had intermittent errors where it couldn't find the tag.

Our this.customTagPaths gets set to something like "#expandPath('/path1')#,#expandPath('/path2')#". We recently moved a folder from path2 to path1 and a page that uses a CT in that folder works great 99.9% of the time. In our logs I even see someone hitting a given page which uses one of the relocated CTs 15 times in the same session and the 16th time it gets amnesia and can't find the tag.

I sort of wonder whether there's 'weird' going on where it sometimes decides on the wrong path and if it can't find it, decides not to look in the other path.

Could be a bug in the CF, or a race condition as mentioned above. I'll probably end up using cfmodule since that is save the other 0.1% of the time as well. :)

Reply to this Comment

Post A Comment

?
You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.