I hope folks will forgive me for not talking about the iPhone again, but here is a good ColdFusion question from Mark:
Good question. When ColdFusion runs onApplicationStart, it runs it in a single-threaded manner. That means if you have code like this:I'm a little confused about using CFLOCK in the Application.cfc file. Is it needed when writing to Application variables and if so from which function (e.g. onRequestStart) Thanks.
<cfset application.startup = now()>
You can rest assured that it will run once, and only once, on your applications first hit.
However, that is the only function that is single threaded for Applications. Every other function in your App.cfc file will not be. (Although onSessionStart is single threaded in terms of your session.) That means if you have some operation that modifies Application variables and if you need to ensure you have no race conditions, then you better use CFLOCK. Here are a few more things to consider.
ColdFusion does not provide a way to restart an application. You have to either restart the server or rename the application. Hopefully this is something that will be fixed in CF9. Most folks, though, just want to rerun onApplicationStart. So you will often see code like this in onRequestStart:
<cfif structKeyExists(url, "reinit")>
<cfset onApplicationStart()>
</cfif>
This lets me rerun the application startup code by just adding ?reinit=1 to the URL. The call will not be single threaded though, and that brings us to the second point.
Don't forget that you only have to care about locking for variables where it really matters. An application startup value is - most likely - not mission critical. If you were to reload the application and someone else did it at the same time, does it really matter if the application.startup is off by 1 second?
Next - if you do need to lock, don't forget that in onSessionEnd, you do not have "direct" access to the Application scope. ColdFusion passes the scope as an argument, and you can certainly modify it via the argument, but you can't do application.x = y. That becomes important when you lock. If you do need to lock your change, you must use a named lock, not a scope lock, within onSessionEnd. And if you use a named lock in one part of your code, than you must obviously use a named lock where you read/write it elsewhere.
Archived Comments
Ray,
Would the isstructkey function be the best to put in the onRequest to check for a session values also if the ultimate goal is to create a structure of ancillary values if the session scope doesn't exist.
"This lets me rerun the application startup code by just adding ?reinit=1 to the URL." Sorry to be trite but doesn't that mean you only have to add "?reinit" to the URL?
This leads to a question I have. On a recent project the architect was content with having the queries in the components use "datasource="#SESSION.dsn#". Is this because the call to the component would be single threaded? I come from the old CF where you locked everything and, in this case, would be using "datasource="#dsn#"" because dsn would have already been copied within a lock from the session scope to the variables scope. Is this not needed any longer?
@Michael: Um, I have no idea what you are asking. If you are asking, 'where do I check to see if a session var exists so I can preset something', then onSessionStart is what you want. But honestly, I can't understand what you really mean here.
@Allen: Heh, that is trite. ;) I can't answer why your dev did this. Those calls where not single threaded. The use of app/session/server is not going to be single threaded unless you cflock em (or put them in onAppStart/onSessionStart. Using the session scope the DSN is probably a bad idea though. I've never seen a production app that uses multiple different DSNs based on session. Most likely he meant to use the app scope, and even then, he should pass the value in to the CFC's constructors and use variables.dsn inside.
I could be wrong, but I've been able to restart a single application by changing the applicationTimeout
If it was once createtimespan(1,0,0,0)
I change it to createtimespan(0,0,0,0), hit a page on the application and it restarts.
Don, you are right, that's another way to do it. I prefer the URL way as I don't have to edit anything.
>> Next - if you do need to lock, don't forget that in onSessionEnd, you do not have "direct" access to the Application scope.
Is this true for onRequestStart as well? I'm creating a single user app for specific users at the office (i.e. one user at a time based on IP address rather than a login and password) and am using App variables for the mechanism to enforce it. I do a lot of checking, locking, and setting of some of those App variables in onRequestStart. Do I need to change all that code to named locks?
No - the onRequestStart/End methods have direct access to the Application scope.
Thanks for the feedback.