Wow! I just discovered that this post has been sitting since February, waiting to be finished and posted. Time flies! Well, now that I've upgraded to the latest version of BlogCFC, it's a good time to add a new post.

In our last post, in this series, we talked about the onApplication event handlers, which automatically fire when a ColdFusion application starts and ends. This go around we'll discuss the onSession event handlers. As you may have guessed, the onSession handlers (onSessionStart and onSessionEnd) wrap a user session. The onSessionStart method fires when a user first visits an application, allowing you to initialize any SESSION scope variables.

To use the SESSION scope you must have sessionManagement enabled in your application. The SESSION scope is a persistent scope used throughout a user's browser session on an application. This is a convenient place to store data that is only pertinent to this specific user experience, like a user object of a specific user, a shopping cart, etc. Execution of the onSessionStart automatically locks access to the SESSION scope within standard application execution, but if called directly you will need to lock the SESSION scope during that manual call.

Similarly, the onSessionEnd executes when a user session times out (the difference between the last request of a session and the sessionTimout set in the Application.cfc). You can use this to perform some final session logging of a specific session or clean-up the SESSION scope to release memory. This is particularly important in an MSOC application, as each session takes up x amount of memory. When you add up the number of sessions in each active application, your RAM utilization can quickly go to the ceiling of your available allocation.

With all of this in mind, it's good to really map out which variables you will place in your SESSION scope. In a shared MSOC configuration, we'v already place items like datasource names and error handlers in our SERVER scope (1 instance), and site information in our APPLICATION scope (1 instance per application). The SESSION scope is a good location for user specific data (only per user/session). If you have a login and authentication system, you can store the user's base information, security level and roles, etc within a few small structs inside your SESSION. You can setup your base user struct, giving that user a unique session id (like a uuid), and then update that struct once the user logs in, or more information is discovered about the user.

view plain print about
2 * FUNCTION onSessionStart
3 * Runs when a user first starts there visit to your application.
4 * The application will initialize if it's not currently active
5 * [through onApplicationStart()]. This method would also run
6 * prior to onRequestStart().
7 *
8 * @access public
9 * @returnType void
10 * @output false
11 */

12    function onSessionStart() {
13        SESSION.isLoggedIn = false;
14        SESSION.user = {userID=0,username="",sessionId=CreateUUID()};
15        lock scope="APPLICATION" type="exclusive" timeout="10" {
16 APPLICATION.users[SESSION.user.sessionId] = SESSION.user;
17 }
18    }
20 /**
21 * FUNCTION onSessionEnd
22 * Runs when a user's session times out, or when explicitly called
23 *
24 * @access public
25 * @returnType void
26 * @output false
27 */

28    function onSessionEnd(required struct sessionScope,required struct applicationScope) {
29        // Remove user from the users struct
30        lock name="appLock" type="exclusive" timeout="10" {
31            StructDelete(ARGUMENTS.applicationScope.users,ARGUMENTS.sessionScope.user.sessionId);
32        }
33    }

Note: One thing to remember, within your onSession methods; If you are accessing an object or variable stored in the APPLICATION scope, remember to use locks when accessing them. Aside from preventing race conditions, it is possible that your onSessionStart can fire prior to the onApplicationStart completing, and the variable you are attempting to access is not yet available. By applying the timeout attribute, you can give the application a few seconds to catch up with the session.

These past few posts have covered two of your most important application event handler blocks, dealing with applications and sessions. In our next round we'll dive into one of the most critical areas: the request.