Welcome!

Bruce Van Horn

Subscribe to Bruce Van Horn: eMailAlertsEmail Alerts
Get Bruce Van Horn via: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Related Topics: ColdFusion on Ulitzer

CFDJ: Article

Ask the Training Staff

Ask the Training Staff

Thanks to all of you for reading this column every month and for sending in questions. Whether or not they get printed, keep 'em coming! I enjoy the interaction and trying to help solve your CF problems.

This month I have room to address only two questions. Both of them, I think, are important to every CF developer out there. So here we go!

Q:You mentioned in your FastTrack to CF class how important it is to lock all references to Server, Application, and Session variables, but you also hinted that there was an alternative to doing this on every page. Could you share that alternative with me?
A:
Absolutely! This subject is covered in detail in Macromedia's Advanced CF class (another shameless plug for you to take these classes if you haven't already!). Let me review the issue before jumping into the solution. As you know (or should know), a variable that is set into the Server, Application, or Session scope is what we call a shared variable. This means that it's assigned a specific slot in the server's memory when it's created and any subsequent reads or writes to that variable are made to that same spot in memory. The problem comes when multiple users access the same pages at the same time. To avoid corrupting the data (or worse) by allowing simultaneous access to a shared variable, we need to place a lock on that variable so only one user accesses it at a time. This can be unwieldy because you need to lock every reference (reads or writes) to those variables. Furthermore, many of us have written apps that are already in production and that use Application and Session variables without any locking. Going back to change these apps can be time-consuming.

The solution offered in the Advanced CF class is easy to understand and, more important, easy to implement. The logic is this: Since shared variables need to be locked but local variables don't, why not copy all our shared variables into local variables at the beginning of each page, reference them as local variables in our code, then copy them back to shared variables at the end of the page to capture any changes? This method makes it easier for you as a developer because you don't have to worry about forgetting to lock a reference to a shared variable. Also, it can improve the performance of your application because you aren't opening and closing locks multiple times on each page for each user.

Here are the steps to freedom: first, place some code into your Application.cfm file, which will execute at the beginning of every page requested (see Listing 1). This code creates an exclusive lock for each variable scope (if you don't use Server variables, just omit this block). Inside the lock initialize a structure called "Data" in the shared scope, then copy any existing data from that scope into an appropriately named structure in the request scope (i.e., Request.Session).

Now that you've copied all the data from the shared scopes into their equivalent Request scoped containers, replace every reference to a shared variable with a reference to its Request scope equivalent. For example, all references to "session.userid" become references to "request.session.userid". That's it! Just add "Request." to the beginning of each variable reference. Since the Request scope is a local variable, no locks are needed.

The last step in the process is to make sure you capture any changes you may have made to these local variables and copy them back into their appropriate shared scope so the next page request is aware of the changes. Remember, the file OnRequestEnd.cfm is the same as Application.cfm except that it executes at the end of every page. Listing 2 shows the code you need to place in OnRequestEnd.cfm to copy the code back into the appropriate scopes. These few lines of code in Application.cfm and OnRequestEnd.cfm can virtually eliminate your shared-variable locking worries.

A problem with this code, however, is that if you set a variable into a shared scope and then do a CFLOCATION to another page, CFLOCATION prevents the code in OnRequestEnd.cfm from executing on that page. In these scenarios set your variable directly into the "Data" structure of the shared variable with a traditional CFLOCK around it, then do your CFLOCATION (see Listing 3).

Q:Sometimes I need to restart my server or make changes to application pages but I'm worried about killing the processes of active users. I want to be able to know how many users are currently using my applications so I can see if it's safe to restart the server or if I should wait until there aren't any active users. Is there an easy way to do this?
A:
Yes! This subject was covered in CFDJ by Christian Schneider in "Live Monitoring of User Sessions" (Vol. 2, issue 8) and I've used his concept on my own servers. His idea is to create a structure in the Application scope (or Server scope if you want to monitor more than one application) that holds users' IP number and a timestamp of their last request. Then you just build a report that loops over that structure to show you the data.

My suggestion is basically the same, but I like to use a query object instead of a structure now that CF5.0 has the ability to run queries from existing queries. Listing 4 contains the code for this, but I'll walk you through the concepts of collecting and displaying the data.

First, create a custom tag (mine is called CF_TrackUsers) that builds a query in the Server scope. You can store as much or as little information about each user as you want. I recommend keeping it simple by storing only some data that uniquely identifies each user (IP number or a unique session ID), the name of the application being used, and the time of the page request. The code in Listing 4 tests to see whether the query exists and creates it if it doesn't. It then tests to see if the data query is old or getting too large (if so, it deletes the old query and recreates an empty query). Last, it inserts a record for this request.

The next step is to place a call to the custom tag inside every Application.cfm on your server to capture data about all your users. The last thing you need is some code that pulls data out of the query to build a report. The code for this report assumes that users aren't active if they haven't requested any pages for more than 15 minutes.

Copy all the code in Listing 4 into Studio and save it in the appropriate places on your server. Now you should be ready to go!

* * *

Please send your questions about ColdFusion (CFML, CF Server, or CF Studio) to AskCFDJ@sys-con.com. Visit our archive site at www.NetsiteDynamics.com/AskCFDJ.

More Stories By Bruce Van Horn

Bruce Van Horn is president of Netsite Dynamics, LLC, a certified ColdFusion developer/instructor, and a member of the CFDJ International Advisory Board.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.