Ask a Jedi: Question on Application based CFCs

This post is more than 2 years old.

David asks a good question about what he thinks may be a possible negative side effect of using Application-based CFCs:

What are the implications of using a single instance of a CFC that all users' requests will access to handle performing some arbitrary functionality compared with just referencing the CFC normally (not stored in Application scope)? The most important part of my question is, do users 2-1000 have to wait for access to the #application.cfcInstance# to perform the arbitrary functionality while it's handling user 1's request?

If not, is it safe to say that using an application-scoped CFC instance could improve performance significantly if it's a CFC whose methods need to be accessed repeatedly by all users?

So first off - no - there is no "locking" involved when it comes to Application-based CFCs. You can have N issues run the same method and they will not have to wait in line. The only exception to this is if you go out of your way to make it act like so. You can add your own locking to a CFC method that could possibly single-thread the access. Unless you do this though the calls will not be handled like that.

Is it safe to say using Application-scoped instances would improve performance? Certainly in CF7 where CFC creation was a bit slow. In CF8 however this slowdown was greatly removed.

I'm wary of saying that this will always increase performance as there are always so many factors that can be in play. I can say though that if your intent is to create a service used by your entire Application, I can't think of a reason not to create it one time only. Now whether you store it in the Application scope or load it via ColdSpring (or whatever), that depends on the application at hand, but in general, I'd recommend creating it once and keeping it in RAM.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by David McGuigan posted on 3/24/2008 at 9:00 PM

Sold. Thanks Ray.

Comment 2 by David Buhler posted on 3/24/2008 at 9:27 PM

Ray,

Can you expand on the use-cases of an application based CFC?

On our app, I have a CFC that as of yesterday, will be hit (quite possibly) 100s of times by one user using a new "AutoSave" feature we introduced. In Flex, when users move from item to item, we save the current work to the DB through our CFC. I'm curious if moving this kind of functionality into the application scope would create a worthy speed difference.

Comment 3 by David Buhler posted on 3/24/2008 at 9:33 PM

Subscribed!

Comment 4 by Raymond Camden posted on 3/24/2008 at 9:49 PM

Well, in _general_, if you have a service used throughout an application, it makes sense to store it in the Application scope. Just like you would store a value used throughout an application.

It sounds like your Flex app is hitting a CC, is it not? I normally would use a CFC 'proxy', by that I mean a CFC that works with the 'real' application-scoped CFCs. This lets me use Application configured CFC from Flex.

Comment 5 by David Buhler posted on 3/24/2008 at 10:02 PM

Not sure what you mean by a "CC".

The Flex app has a wizard. The Wizard is between 9 and 13 steps, depending on the options you choose. Flex makes a request on a CFC with a method called "Update" each time the view changes. This logic was just added, because we had kept all the information "in state" on the client, but some people clicked the HTML Header, or their Favorites, or their Home Button, and lost 9-13 steps worth of work. :)

I guess my confusion lies in defining when I wouldn't create my CFCs in the application scope and when I would. For example:

The "Login" CFC would run each time a user hits the app.
The "Fetch Regions" CFC would run each time a user hits the app.
The "UpdateEvent" CFC would run each time a user hits the app.

I could theoretically store all of the above in the application scope. Is that reasonable? Are there drawbacks? What kind of speed gains are there to storing a CFC in the application scope?

Comment 6 by David Buhler posted on 3/24/2008 at 10:04 PM

"I normally would use a CFC 'proxy', by that I mean a CFC that works with the 'real' application-scoped CFCs."

Are you loading the CFCs into application scope in the Application.cfc?

Comment 7 by Raymond Camden posted on 3/24/2008 at 10:07 PM

David: My first 'CC' was 'CFC', sorry. Yes - I do normally load all my CFCs into the App scope - I say normally because I'm slowly moving to ColdSpring.

I can't tell you if it makes sense to use the App scope w/o knowing even more about your app. It depends! First off - remember you can't hit an Application scoped CFC via Flex. You have to hit a proxy CFC instead that would integrate with the Application scoped CFC. There really aren't any drawbacks if you are using CFCs are basic services, which it sounds like you are.

Comment 8 by Daniel Budde II posted on 3/24/2008 at 10:19 PM

David, I would say 'yes', Ray regulary uses components scoped in the application scope. Take a look at his blogcfc or galleon. As Ray said earlier, it is a very easy way of having access to an object throughout your application and if you tack on an object factory to that, then you have a method that should help ensure you are only using one instance of a component always. Although, if you were to always use, lets say 'application.user' for a user object, that is relatively easy to be using the same instance throughout your application.

Regarding the proxy CFC, one example of that would be if you had a 'user' component with an 'authenticate' method, but you needed to be able to authenticate through a flash client, you could create a proxy cfc 'remote' access method named 'userProxy.cfc' and have a remote method in it named 'authenticate' that calls 'application.user.authenticate()' and this way you have a controled method for breaking encapsulation within a cfc.

Hope that makes sense.

Comment 9 by Daniel Budde II posted on 3/24/2008 at 10:22 PM

Bah, by the time I responded, Ray had already answered.

Comment 10 by Raymond Camden posted on 3/24/2008 at 10:26 PM

One thing I want to point out - BlogCFC is NOT what I'd consider best practice. I love it- but it's a bit rusty. That's why BlogCFC6 is a rewrite. Galleon is definitely done a bit nicer.

Comment 11 by David Buhler posted on 3/24/2008 at 10:30 PM

Still much appreciated from both of you.

I'll give it a shot tonight. I'm curious as to the speed difference.

Comment 12 by Raymond Camden posted on 3/24/2008 at 10:40 PM

You probably won't see a lot - especially if you are under CF8. But again - I prefer to create things one time only if I can get away with it.

Comment 13 by David McGuigan posted on 3/24/2008 at 10:51 PM

I would think that any noticeable "speed" differences wouldn't surface until you were dealing with large magnitudes of simultaneous requests; Ray mentioned that with CF 8 a lot of the CFC instantiation overhead was reduced or eliminated.

The application that sparked my initial question can have thousands (and hopefully tens of thousands soon) of users navigating the site at the same time, so moving to a set of application-scoped CFCs, I'm hoping, should cut out a lot of unnecessary workload fat.

Beyond performance though, a side benefit I've noticed is that it just makes sense and seems more logical to store a single instances of CFCs in the application scope from a development standpoint. I much prefer using:

<cfSet wtf = application.instance.freakOut('#session.idUser#', '#now()#') />

to

<cfinvoke component="aksl.sjd.jsdfj" method="freakOut" idUser="#session.idUser#" timeStamp="#now()#" returnVariable="wtf" />

Comment 14 by Michael posted on 3/24/2008 at 10:54 PM

I would also suggest including an application reset code in your application.cfc to detect presence of a URL variable...appreset.cfc this will allow for grabbing new versions of your cfc's if there is a change.

<cffunction name="appStart">
<cfset application.users = CreateObject("component", "cfc.users")>

</cffunction>
<cffunction name="onApplicationStart">
<cfset this.appStart()>
<cfreturn true>
</cffunction>
<cffunction name="onRequestStart">
<cfif IsDefined("URl.AppReset")>
<cfset this.appStart()>
</cfif>
<cfreturn true>
</cffunction>

Comment 15 by David McGuigan posted on 3/25/2008 at 12:06 PM

Michael! I cannot even articulate how helpful that is. I had been either developing the CFC external to the app scope and then when I thought it was ready moving it over OR restarting the CF service for each new test. GENIUS.

I'll also take this opportunity to act like a grown up and mention that, "Kids, the example Michael showed above is for development purposes only. When you move your application to a production server, you need to amputate the ability of anonymous users to reset it. Slash stay in school" - Grown Up Dave.

Thanks Michael.

Comment 16 by Raymond Camden posted on 3/25/2008 at 3:24 PM

David, you don't have to remove it in production. A 'reset' isn't always that big of a deal. You can also make it check url.appreset for a particular value, like url.appreset=cowseatchicken. This means that only people who know the right password can reset it.

Comment 17 by Brian Kotek posted on 3/25/2008 at 9:54 PM

The main factor in determining whether a CFC is a candidate for being a Singleton and going into the application scope is whether or not it has state.

Things like Services (the API to the model) and Gateways (CFCs that deal with database queries) are usually great candidates for the application scope because they have no instance data. You just pass in arguments and get back a result.

On the other hand, CFCs that have state (often called "business objects") do have state, and these are usually created on a per-request basis. They're also called "transient" objects because they only stick around for one request. So something like a User CFC, or an Address, or a Company, do contain state since they represent specific entities. So those would not be good for the application scope (in fact they'd probably be really bad).

Hopefully that helps a bit.

Comment 18 by David Buhler posted on 3/25/2008 at 10:00 PM

My understanding is that the client has state and the Database has state, but how would you preserve state in the CFC, even in the application scope, once the request ends?

Comment 19 by Brian Kotek posted on 3/25/2008 at 10:02 PM

I should modify that to say "The main factor in determining whether a CFC is a candidate for being a Singleton and going into the application scope is whether or not it has state *that changes or varies between users or requests*."

Singletons can certainly have instance data, it just generally doesn't change once the CFC has been created.

Comment 20 by David McGuigan posted on 3/25/2008 at 11:10 PM

David B:
The "state" would be represented by the current values of the CFC's properties at any given time. As users and code interact with the application, the CFC's instance variables' values can change, thereby altering its state.

By placing a CFC instance in the application scope, you're ensuring that it, and its properties/state will live before, during, and after each subsequent request until either ColdFusion is restarted or some other mechanism overwrites the instance with a new instance (such as Michael's user-triggered appStart function above).

Comment 21 by David McGuigan posted on 3/25/2008 at 11:21 PM

While we're on the subject:
Can you not call Application.cfc methods from ordinary application-child code?

I have these two methods in Application.cfc:

<!--- f: onApplicationStart --->
<cffunction name="onApplicationStart" returnType="boolean" output="false">

<!--- Initialize application variables --->
<cfreturn reinitializeApplication() />

</cffunction>
<!--- x: onApplicationStart --->

<!--- f: reinitializeApplication --->
<cffunction name="reinitializeApplication" returntype="boolean" output="false" >

<!--- Etc. --->
<cfreturn true />

</cffunction>
<!--- x: reinitializeApplication --->

Although the application correctly initializes as predicted, when I call reinitializeApplication() from the Index.cfm file for example, I get this error:

Error: The initializeApplication method was not found.

Here's the code that calls it, I'm not sure what I'm doing wrong.

<!--- Check for an application reset trigger (development purposes only) --->
<cfif etc eq 'Reset'>

<cfset application.initializeApplication() />

</cfif>

Any ideas? Can you just not call Application.cfc methods outside of the file?

Comment 22 by David McGuigan posted on 3/25/2008 at 11:25 PM

Note: I realize that in the last chunk of code I accidentally pasted "initializeApplication" instead of "reinitializeApplication". Whoops.

Just ignore that. The same problem still exists even when I attempt to call the correct function name.

Comment 23 by Michael posted on 3/25/2008 at 11:28 PM

In your Application.cfc onApplicationStart
you can include this line
<cfset application.applicationCFC = this>

then in your index file and any other file in your application you can reference application.applicationCFC.resetApp or whatever.. I haven't tried this reference but it should work.

Comment 24 by Raymond Camden posted on 3/25/2008 at 11:29 PM

@Dave - do you mean, can I call 'core' App.cfc methods from other methods in App.cfc? Yes. Any method can call any other methods. Just be aware that when you call a 'core' method, like onSessionEnd, it doesn't REALLY have the samep impact. Ie, you can't kill a session, only CF can. Also note that methods which are single threaded, like onAppStart, will NOT be single threaded if you call them youself.

Comment 25 by David McGuigan posted on 3/25/2008 at 11:47 PM

Ray:
I just meant outside of the Application.cfc file, particularly, non-core methods (in this case reinitializeApplication, my custom function).

Michael:
That did it! Exactly what I was looking for. Thanks!

Comment 26 by Raymond Camden posted on 3/25/2008 at 11:49 PM

If I had stuff I wanted to call from my app, and from app.cfc, I would not put the methods in app.cfc. I'd put them in another CFC, and make an instance of that CFC in the app.cfc file.

Comment 27 by David Buhler posted on 3/26/2008 at 12:19 AM

I still wish this type of functionality...the ability to restart the application from a URL parameter or the creation of a "down for maintenance" page, was part of an off-the-shelf, Adobe framework for CF. It seems to be standard practice for all of the more experienced developers.

Comment 28 by Raymond Camden posted on 3/26/2008 at 12:28 AM

I don't know - I mean - rerunning onAppStart is simple enough with a hook in onRequestStart. You don't need a 'real' restart truly, you just want to reload your application variables. Doing a real app restart has consequences beyond your code - like in active sessions, etc. So in general, I don't think you really need that kind of power, although, I know I've asked for it myself in the past, so maybe I'm being difficult. ;)

Comment 29 by David McGuigan posted on 3/26/2008 at 1:23 AM

I have to agree with / be as difficult as Ray here.

As far as a sitewide maintenance mode, Adobe HAS __kind_of__ provided this for us (I don't know what that underscore syntax means, I've just seen Ray use it before so thought I'd give it a shot).

The onRequestStart method. All we have to do is flip the switch and decide what to show instead.

I wrote this the other day, it's a pretty good example of just how easy ColdFusion makes it. This code goes in the onRequestStart method (probably before anything else).

<!--- Sitewide maintenance mode mechanism. Intercepts any request for site content and aborts it, serving alternate content --->

<!--- Just set sitewideMaintenanceMode to true to activate --->
<cfset sitewideMaintenanceMode = false />

<!--- If sitewide maintenance mode is active, serve alternate content and abort processing on every request --->
<cfif sitewideMaintenanceMode >

<cfinclude template="/Mechanics/AlternateContent/Maintenance.cfm" />
<cfabort />

</cfif>

The coolest thing about it is that you can have various modes and pre-written messages and just toggle them with simple variable / content pairs. In reality you could even move the sitewideMaintenanceMode variable into a password-protected database table and trigger it from a web-based administrator.

Long story short, ColdFusion saves lives.

Comment 30 by David McGuigan posted on 3/26/2008 at 1:36 AM

Note: In order for this to do what it should all of your application pages should be ColdFusion files. As far as I know, there's no way to let ColdFusion get at and intercept non-ColdFusion file requests (like .htm or .css files).

Although, I'm curious as to whether you could just set handlers for other file types on your Web server and have CF pre-empt them too.

I just tried setting CF script map for the .htm type in IIS 7 and it serves "The service is unavailable". I don't know that much about Web server configuration, but this is kind of an interesting concept. It'd let you protect a lot of non-CF content(like .jpg files for example)from being accessed directly through URLs.

Anyone IISperts out there that can answer this?

Comment 31 by David Buhler posted on 3/26/2008 at 6:47 PM

@Dave

I think the "Down for Maint" page is going to need CFHeaders added to let the Search Engine Spiders know that the page is down for "X time" and the redirect is temporary in nature.

This type of functionality should be built in to the App.cfc when it's first generated, I think, because:

1) it's commonly used
2) the details are important

I'd just argue that the Coldfusion framework is well done by Adobe, but Adobe should still support their own homegrown framework with this type of functionality built in.

Comment 32 by Derek posted on 8/29/2009 at 6:42 PM

How well does this work when the Application scope is being duplicated to be put on the request? Looking at some old code that is doing this and I'm concerned that creating Singletons in the application scope would be a waste if they are being copied to the request.

Comment 33 by Raymond Camden posted on 8/29/2009 at 6:43 PM

Simple - don't duplicate the App scope to the Request scope. That was done in CF5 days when the App scope had memory leak issues. It has not been needed, nor recommended, for years.

Comment 34 by Derek posted on 9/27/2009 at 4:46 AM

Thanks. That will be fun ripping that stuff out. Setting complex variables is done by reference in CF, right? So if it was doing <Request.app = Duplicate(app)>, I should be able to convert that to <Request.app = app> right? Is locking still needed on the app scope? If so, for reads and writes or just writes? I'm on CFMX7 if that makes a difference.

Thanks!

Comment 35 by Raymond Camden posted on 9/28/2009 at 12:25 AM

By ref, yes. Yep to your second question. No - you don't need to lock just because you use the app scope - you only need to lock when you are concerned about race conditions.

Comment 36 by Zdenek Picha posted on 10/22/2009 at 4:33 PM

I have found this page:
http://www.alagad.com/blog/...
showing memory leaks if duplicate not used.

"This simple example is just an illustration of how you can get yourself into trouble when pointing a reference to objects from a shared scope like application or server, into a local scope like request. When we make a link from the request scope into the application scope, it maintains a reference such that the request variable would never go away until the referencing application variable gets garbage collected (which would wait for the application timeout). By duplicating the object into the request scope instead, this ensures there is no reference to the application scope variable, which allows it to be cleaned up after the request completes."

Can we really believe these leaks are over?

Comment 37 by Raymond Camden posted on 10/22/2009 at 4:54 PM

Than I suppose it just makes sense to _not_ use the request scope. Really it was only useful pre-MX days.

To be clear, I mean to use the Request scope as a duped copy of app.whatever.