It's pretty common to use the application scope to cache components. If your component is a collection of methods or data access functions it's often faster to put them into the application scope than it is to create an instance with each request. Now you probably know that you should quality all of the variables in a function with the "var" key word. This insures that the variable exists inside the "scope" of the function call. This allows multiple function calls to be made to the same instance without one set of variables over writing the other.
One of the areas where this can be difficult to manage is when using a ColdFusion tag that creates its own scope. Take CFHTTP as an example.
Consider this "test.cfc" component.
The function "dumpthis( )" dumps out 2 scopes that exist within the scope boundaries of the component - "this" and "variables".Now consider this test framework.
This code instantiates the "test" CFC in the application scope if it does not already exist and then runs a call to "test" (the function retrieving the yahoo page). It dumps out the “this” scope and “variables” scope that belong to the component. If you run the test you will notice that a cfhttp variable containing the Yahoo content is a part of the "variables" scope inside the CFC.
Finally, the code runs the function "test2()", which retrieves the cfwebtools page. The dumpthis() functions shows that now the variables scope contains a cfhttp variable that contains the cfwebtools content.
Maybe you are saying, “So what ... that's what I would expect”. But the implications reach a bit farther than that. What is actually going on here is that the variables scope that is local to the CFC is persisting in the application scope. In fact, once you have run the code above put the following code on a separate script within the same application.
You will notice that, even though you have not called either test() or test2(), the variables scope still contains a cfhttp variables and the "filecontent" key still contains the content of the last cfhttp call made. How would this a problem? Let's say that 2 requests arrive simultaneously - one designed to return the results of "test()" (the yahoo page) and the other designed to return the results of test2() (the CF Webtools page). One request could overwrite the other and they could both get the same content even though they both fired different functions from entirely different request threads. Consider the implications for a web service, stock quotes, tracking information etc. You could cause yourself some real data headaches.
How to fix it? Luckily there is a useful attribute called "result" that you can use for your CFHTTP call. The fix is to var the result variable and then use it as an attribute to your CFHTTP tag:
Of course in addition to CFHTTP there are other Coldfusion tags that create special scopes (cffile with the "upload" action for example). As a rule of thumb when you are caching CFCs in the application scope, take an extra look at any calls to external resources made from within a function.
And now, dear readers, I'm sure that some of you will be tempted to comment on whether you should or should not be using the application scope in this way. Please understand that the muse believes there are folks on both sides of the issue that have a legitimate point of view - and keep the comments charitable.
Related Blog Entries