Learning ColdFusion 9: Resetting Applications With ApplicationStop()

Posted July 29, 2009 at 2:16 PM

Tags: ColdFusion

This morning, as I was starting to learn more about ColdFusion 9's new Object-Relational Mapping (ORM) functionality, I came across a new system function: ApplicationStop(). In the context of ORM, you can call ApplicationStop() to reset the application such that all of the ORM configuration files and settings will be rebuilt. Since these files are only built when the application starts up, ApplicationStop() gives you the ability to "force quit" an application such that the next page request will restart the application and therefore rebuild all of the ORM configuration files. While this makes less sense in production, I can see that having the ability to flush ORM settings as you make changes to your database and your model during development (much like the RefreshWSDL attribute in the CFInvoke tag), will be quite awesome.

This same functionality - the rebuild of the ORM / Hibernate configuration and mappings - can also be accomplished using the ORMReload() method. So this got me thinking: if this can be done in two different ways, then maybe ApplicationStop() has a wider benefit? I wanted to get a better sense of what was going on when this method, ApplicationStop(), was called, so I set up a really simple application to test application and session persistence.

To me, sessions are very tightly coupled to the application under which they exist. As such, the test application needed to have session management turned on:

Application.cfc

 Launch code in new window » Download code as text file »

  • <cfcomponent
  • output="false"
  • hint="I define the application settings and event handlers.">
  •  
  • <!--- Define the application settings. --->
  • <cfset this.name = hash( getCurrentTemplatePath() ) />
  • <cfset this.applicationTimeout = createTimeSpan( 0, 0, 5, 0 ) />
  • <cfset this.sessionManagement = true />
  • <cfset this.sessionTimeout = createTimeSpan( 0, 0, 3, 0 ) />
  •  
  • <!--- Define the request settings. --->
  • <cfsetting showdebugoutput="false" />
  •  
  •  
  • <cffunction
  • name="onApplicationStart"
  • access="public"
  • returntype="boolean"
  • output="false"
  • hint="I initialize the application.">
  •  
  • <!--- Initialize the application settings. --->
  • <cfset application.dateInitialized = now() />
  •  
  • <!--- Return true so that the page can load. --->
  • <cfreturn true />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="onSessionStart"
  • access="public"
  • returntype="void"
  • output="false"
  • hint="I initialize the session.">
  •  
  • <!--- Initialize the session settings. --->
  • <cfset session.dateInitialized = now() />
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  • </cfcomponent>

As you can see in this code, our Application.cfc only has two methods, OnApplicationStart() and OnSessionStart(). Each of these methods creates one scoped variable to mark the time at which the scope was initialized. We will be using these time stamps in the next page, index.cfm, to output the relative age of each scope (Application and Session):

Index.cfm

 Launch code in new window » Download code as text file »

  • <!---
  • Param a variable in the application. We are doing this
  • outside of the OnApplicationStart() method to test whether
  • or not the application was truly killed of if the above
  • method was simply called.
  • --->
  • <cfparam name="application.hitCount" type="numeric" default="0" />
  •  
  • <!--- Increment the hit count. --->
  • <cfset application.hitCount++ />
  •  
  •  
  • <cfoutput>
  •  
  • <h1>
  • Application And Session Overview
  • </h1>
  •  
  • <p>
  • Application hit count: #application.hitCount#
  • </p>
  •  
  • <p>
  • Application initialized:
  • #dateDiff(
  • "s",
  • application.dateInitialized,
  • now()
  • )#
  • seconds ago.
  • </p>
  •  
  • <p>
  • Session initialized:
  • #dateDiff(
  • "s",
  • session.dateInitialized,
  • now()
  • )#
  • seconds ago.
  • </p>
  •  
  • <p>
  • <a href="reset.cfm">Reset application</a> &raquo;
  • </p>
  •  
  • </cfoutput>

As you can see in this code, we are outputting the age of both the Application and the Session scopes based on their DateInitialized time stamp. We are also defining and incrementing a new Application variable to record the hit count to this page. I am using this hitCount variable to see if the Application is truly reset, or if the OnApplicationStart() method is simply called again. If the application was not truly reset, then this extra-method variable assignment would not be reset.

At the bottom of the page we are providing a link to reset the application. Normally, this kind of link would end up triggering code within the Application.cfc that might look like this:

 Launch code in new window » Download code as text file »

  • <!--- Check to see if reset flag exists in URL. --->
  • <cfif structKeyExists( url, "reset" )>
  • <cfset this.onApplicationStart() />
  • </cfif>

Here, we are manually calling the application initialization function from within the Application.cfc itself (usually from within the OnRequestStart() event handler). But, using this new ColdFusion 9 method, ApplicationStop(), we are doing this implicitly:

Reset.cfm

 Launch code in new window » Download code as text file »

  • <!---
  • Stop the application. After calling this method, the next
  • page request to the application should start it up again
  • (resetting it).
  • --->
  • <cfset applicationStop() />
  •  
  • <!--- Redirect back to overview. --->
  • <cflocation
  • url="index.cfm"
  • addtoken="false"
  • />

As you can see, this code just stops the application and then redirects the user back to the overview page. At this point, the application has stopped and the next page request (precipitated by the CFLocation tag) should restart the application.

When I refresh the overview page a few times, I get this output:

Application And Session Overview

Application hit count: 5
Application initialized: 41 seconds ago.
Session initialized: 41 seconds ago.

Then, when I click on the "Reset application" link, I end up back on the overview page with the following output:

Application And Session Overview

Application hit count: 1
Application initialized: 3 seconds ago.
Session initialized: 91 seconds ago.

As you can see, the entire Application scope was wiped out and the OnApplicationStart() method in the Application.cfc must have executed to reset the DateInitialized property. But, the Session scope was not changed at all! Whether or not this was done on purpose, I think that this is a bug in the ColdFusion 9 application architecture. I strongly believe that when an application stops, all of the sessions within it should stop as well. Remember, these are not two completely independent entities - the Application might contain references or aggregates of the Session data. If the Application resets and the Sessions continue to live on, unaltered, then potentially troublesome discrepancies could form between the two memory pools.

When I saw that ColdFusion 9 provided two ways to flush the ORM / Hibernate configuration and mappings, I thought that maybe one of these methods - using ApplicationStop() - might have additional benefits in terms of allowing us to restart applications (something that has before only been available via hacks). After some testing, it seems that ApplicationStop() allows us to reset an Application, but only partially, leaving the Session scopes untouched.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page


You Might Also Be Interested In:



Learning ColdFusion 9 - ColdFusion 9 tutorials, samples, examples, demos

Reader Comments

Jul 29, 2009 at 2:24 PM // reply »
6,516 Comments

I am waiting to hear some feedback before I file this issues (sessions not be reset) as a bug. Let me know what you think. I am *strongly* inclined to think it is a bug, but would love to hear other people's thoughts.


Jul 29, 2009 at 2:45 PM // reply »
31 Comments

I agree, for me the expected behavior when resetting the application would be to also clear all the sessions.


Jul 29, 2009 at 2:58 PM // reply »
25 Comments

I'm somewhat on the fence here. I guess it is because I'm used to using frameworks such as Model-Glue and Mach-II where I reload the framework when making changes. To do this I call onApplicationStart() which essentially resets the application. It does not affect the sessions.

It seems logical that stopping the application should clear out sessions, but unless you've coded it to do so, the application does not know about sessions. The app knows only about application scoped variables.


Jul 29, 2009 at 2:58 PM // reply »
68 Comments

I'd love to comment on this, but there appears to be no documentation for ApplicationStop in Adobe's documentation:
http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WS890819DC-DE4D-4b24-A237-6E3483E9D6A1.html

It mentions the method, but offers no link for a full definition.


Jul 29, 2009 at 3:09 PM // reply »
6,516 Comments

@Andy,

Yeah, the only other place that I could find that mentions it is in the ORM section, very briefly, as an after thought (see last line on page):

http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSB51B3786-8E55-4a72-ABDB-5707B9A853D9.html

@Matt,

Right now, it's hard to compare this to anything because traditionally, we've only been able to "hack" this functionality. As such, I don't think we should make any decisions based on existing frameworks as this really is new functionality.

That said, my gut tells me that resetting an app should reset all sessions. Should a session ever exist outside of an application? That just seems off to me.

As a follow up to that thought, perhaps we should think about whether or not a Session should ever have a higher timeout than an Application? If we agree that a session should exist outside of an application, then *yes* a session can / might have a higher timeout. But, if *no*, then session are tightly bound to their parent application.

Hmm, maybe I'll give that a quick test.


Jul 29, 2009 at 3:10 PM // reply »
111 Comments

I actually think the behavior works correctly.

If you're forcefully "stopping" an application because you've rolled out structural changes, then you should be clearing everything about the application to ensure that application works correctly.

If you were to make a change that affects the the SESSION scope, then using the applicationStop() is a way to reset the application w/out needing to restart the application server.

So, I think the behavior is the safest method for handling the issue.

However, I could see the usefulness of being able to keep sessions active, so perhaps an additional argument could be added to keep sessions alive.


Jul 29, 2009 at 3:14 PM // reply »
6,516 Comments

@Dan,

I am sorry, I am not following you. Are you saying that the way ApplicationStop() is working now is what you think is correct?

Think about doing something like changing your Application-cached Factory that is responsible for creating things like Session-cached User objects. To me, it seems that if anything changes in the Application, it might have fallout that directly affects items created and cached in the session. As such, to me, the full-wipe across both memory pools seems the safest default.


Jul 29, 2009 at 3:20 PM // reply »
25 Comments

The main reason I mentioned the framework reloading is because it is primarily done for the same reason: to reload any configuration changes (including ORMs such as Reactor or Transfer). I agree new functionality shouldn't be based on that practice though.

I guess it would be interesting to know if the Hibernate ORM session management is in any way tied to the traditional user session. I would guess not because you wouldn't want to restart an app to load new ORM changes but a user's existing session had old ORM info.

I'm awaiting your test results of timeout tests as that should show how the CF server defines the relationship between app & session.

Curious though, is there a way now (pre CF 9) to wipe out all existing sessions, short of restarting the CF service?


Jul 29, 2009 at 3:53 PM // reply »
35 Comments

I have to disagree here, Ben. If you have your Session and your Application intermingled, that's something you need to work out. Forcing a reset of all Sessions could be suboptimal.

My counterexample would be a simple (one-server) eCommerce site. My Session stores login information, cart contents, etc. That information absolutely should survive a reset of the Application. If I need to bounce the Application, say because I'm hitting a memory/performance hit with my cache logic, or because I need to apply a security patch, I lose money if the dozen or hundred people on my site suddenly lose their cart contents.

(Yes, it's a contrived example. Presumably, I have more robust cart/login info than that. But that's not the point.)

I mean, I see what you're getting at -- if you have that level of intermingling then it could cause you serious headaches. Maybe it should have a resetSessions parameter?


Jul 29, 2009 at 3:54 PM // reply »
31 Comments

Have you tried setting a reference to an app-scoped value in your session, and seeing what happens to it using your reset two different methods?

In application.cfc:

onApplicationStart()
cfset application.teststruct = StructNew()
cfset application.teststruct.initialized = Now()

onSessionStart()
cfset session.teststruct = application.teststruct

Then dump the session variable in your index.cfm.

I think what is displayed in the dump will determine how I feel about the issue.


Jul 29, 2009 at 4:58 PM // reply »
53 Comments

I agree with those that have said it would be nice to have an option to clear the session scopes, but I do not think it should do it automatically. Just like with everything else in ColdFusion, it would be nice to have options.

Clearing out the session is not always optimal, as Rick said, and in some cases it could be considered critical that they not be. In fact, though I have not tested this yet, in reading I believe it is possible to deploy your application in a way were sessions will even persist beyond a server restart.


Jul 29, 2009 at 5:07 PM // reply »
6,516 Comments

As it turns out, I am quite wrong. It seems that this is completely inline with the default behavior of the ColdFusion application framework. I just did some relative timeout testing in ColdFusion 8 and found the exact same results:

http://www.bennadel.com/blog/1668-Understanding-Application-And-Session-Timeouts-In-ColdFusion.htm


Jul 29, 2009 at 6:07 PM // reply »
34 Comments

Yeah, I was going to say something but you got to it before I could Ben. This new application function is great. It opens up a lot of doors, as your probally all ready know.


Jul 30, 2009 at 6:30 PM // reply »
45 Comments

I personally believe that sessions are directly related to the application and should be reset with the application, however since the ColdFusion application framework is not setup that way; I am happy to second the request for a stop session flag in applicationStop().

@Rick,

With your cart example, how do you handle session timeouts?


Jul 30, 2009 at 11:16 PM // reply »
34 Comments

I actually like the fact that it doesn't kill the sessions. I think it has many advantages for it to not kill the application. Assume that the user wishes to restart the application, or switch applications without having to login or authenticate again


Aug 2, 2009 at 12:33 PM // reply »
54 Comments

hey guys,

Ben and I spoke briefly about this on twitter the other day but I thought I'd come and have another read through this post.

I like the idea of being able to stop an application programmatically like this, however as a few other people have said plenty of us already mimic this kind of functionality using the onApplicationStart() method called from onRequestStart() using an init key in the URL, this is also something built into many of the frameworks so I'm not quite sure what 'value' this really adds to the product.

Where I would really like to see adobe go with this is giving application run control in the admin panel on a per-application basis allowing us to stop/start/pause applications individually without the need to restart the entire cf server.

I've found on several occasions that I'll perhaps have a bug or bottleneck on an individual application which takes me a while to trace, until the issue is addressed the application just sits there hung in an infinite loop or something and this forces me to restart the entire server which hosts a whole bunch of applications all of which then have to reinit, potentially also killing any sessions which are active within those apps at the time of reset.

Being able to stop individual applications from within the admin would be such a great benefit to me and many others I'm sure and if Adobe already have this groundwork in place I'm sure it wouldn't require much work on their part to factor it in.

Does anyone else have a thought on that?

Rob


Post Comment  |  Ask Ben

Recent Blog Comments
Nov 20, 2009 at 11:32 PM
Five Months Without Hungarian Notation And I'm Loving It
I've used headless camel case for years for not only ColdFusion variables, but also SQL tables and fields... pretty much everything involving code. I also subscribe to the "don't abbreviate and clea ... read »
Nov 20, 2009 at 11:00 PM
Five Months Without Hungarian Notation And I'm Loving It
@Marcel, Yeah, I always err on the side of longer but more readable variable names. As for the camel casing of CF methods and the headless camel casing of custom items, I get around this by always ... read »
Nov 20, 2009 at 10:56 PM
Five Months Without Hungarian Notation And I'm Loving It
I use the following and love it: my.namespace.MyComponents.functionMethodsOrUDF() CONSTANT_VALUES_OR_PROPERTIES One thing I always try is to CamelCaseBuiltInColdFusionFunctions() so others can tell ... read »
Nov 20, 2009 at 5:38 PM
Learning ColdFusion 8: CFImage Part I - Reading And Writing Images
Hi Ben, Great article. I've been looking around to see if ColdFusion image engine can programatically create the following "wrap around" effect: http://www.creativepro.com/article/photoshop-s-she ... read »
Nov 20, 2009 at 5:35 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
@Dave: I talked to Gert he suggested: <cfhttp method="get" url="http://{some cf website}" result="stuff" addtoken="yes" /> Note the addition of cfhttp attribute addtoken. That should persist y ... read »
Nov 20, 2009 at 5:23 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
@Todd, Ahh, gotcha, yeah that makes sense. ... read »
Nov 20, 2009 at 5:17 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
Ben, sorry if I didn't make this clear. You can make it work like that if you want, just put <cfset session.foo = 1> (and <cfset application.foo = 1>) in your OnRequestStart() and it reve ... read »