2

I am using components rather extensively in my ColdFusion application, and run into a frequent error that my components are undefined, although they definitely ARE defined.

I am defining the components in my Application.cfc file.

 <cfset cfcList = "component1,component2,component3">
 <cfloop list="#cfcList#" index="local.thisCfcName">
      <cfset application.cfc[local.thisCfcName] = createObject(
        "component",
        "#application.cfcPath##local.thisCfcName#"
      )>
  </cfloop>

What I have been able to determine: In my onRequestStart function, I am restarting the application on encountering 'init' url variable:

<cfif structKeyExists(url, "init")>
  <cfset onApplicationStart()>
</cfif>

It seems that while the application is reinitializing, any other user trying to access the component at that moment will get the following error (the component that fails can vary).

[diag]=Element CFC.COMPONENT1 is undefined in a Java object of type class [Ljava.lang.String; referenced as ''

Is there something I am doing incorrectly here that can solve this issue? I get these errors several times a day, and there must be a resolution, but I have not been able to find any information about this particular issue.

WillardSolutions
  • 2,316
  • 4
  • 28
  • 38
johnwangel
  • 47
  • 8
  • 1
    Why are you restarting the application that frequently? – WillardSolutions Dec 21 '18 at 14:48
  • When anyone goes to the home page, it restarts to make sure their application refreshes with any code updates. Is there a better way to do this. Every example application I've seen does this. – johnwangel Dec 21 '18 at 14:51
  • What odes your `onApplicationStart()` function have in it? – James A Mohler Dec 21 '18 at 14:55
  • 2
    That's probably not what you want. You probably want `onSessionStart` or `onRequestStart`. If you're making frequent code changes to the app so that this is an issue, you should also rethink your code delivery pipeline – WillardSolutions Dec 21 '18 at 14:56
  • @JamesAMohler onApplicationStart() only contains the first snippet in my post, plus defining 3 other application variables. – johnwangel Dec 21 '18 at 15:06
  • 1
    "Every example application I've seen does this." Out of curiosity, where are you seeing these examples? And are they really being used for what you think they're being used for? Frequent application starts to pick up new code sounds like you are either deploying to production too often or are developing on production. – Shawn Dec 21 '18 at 17:07
  • The other commenters are correct, you should really rethink your code delivery pipeline. CI/CD is a solved problem. If you need to update your code in prod (e.g. hotfix), you could have a `cfinclude` in your onRequestStart that re-initializes any components that you have made changes to. – Seanvm Dec 21 '18 at 17:22
  • Could you do a `` just to see what gets in there? – James A Mohler Dec 21 '18 at 17:40
  • You could try `applicationStop()` instead of `onApplicationStart()`. This will leave the sessions intact. I'm not sure if calling `onApplicationStart()` will fire session stuff. Also, I think it can continue parts of the application that are actively running without killing the application underneath them. I'd have to test. – Shawn Dec 21 '18 at 18:02
  • Though I guess I should start with, which version of CF are you using? After seeing more than one CFMX question in the last couple of months, I can't assume that people are running on more recent versions of CF. :-S – Shawn Dec 21 '18 at 18:05
  • And off topic, but I would strongly suggest that if this is new development and you're able, I'd switch to using script-syntax over the older tag-syntax. It's a lot more useful in the long run and a lot more capable in modern versions. – Shawn Dec 21 '18 at 18:06
  • 1
    I have never seen a cf app refresh it’s cached components every time a user does something. I’ve seen a lot of sites allow some sort of app refresh by calling onApplicationStart() inside onRequestStart(), but it’s usually triggered by an admin/dev very infrequently. Why would code be changing in production so frequently that you let regular users trigger the app refresh? – Redtopia Dec 21 '18 at 18:09
  • 1
    One other concern that you should watch out for is that if I automate a ton of calls to `https://yourwebsite.com?init`, then I can easily DOS your site. I would suggest that if you need that functionality, there be some serious rate-limiting checks or even better a way to only allow admin users to use that. – Shawn Dec 21 '18 at 18:16
  • Thanks everyone. These are some good suggestions. I am going to look into restructuring this and will return with any solution I find. – johnwangel Dec 21 '18 at 20:55
  • Thanks for the suggestions. I spoke with the developer who had added the init variable to all the page requests, and we determined that there was a better way to accomplish what they were trying to do with that. So I was able to remove the init variable, which seems to have resolved the issue. – johnwangel Dec 24 '18 at 15:33

1 Answers1

3

To answer your question, you're almost certainly running into race conditions. CF only locks the application scope when the application first starts:

Runs when ColdFusion receives the first request for a page in the application

After that, if you call OnApplicationStart() explicitly:

... ColdFusion does not start the application; it does execute the method code, but does not lock the Application scope while the method executes.

So any other thread/request trying to read from the application scope may get errors, because the first thread is still modifying the scope at the same time. You'd need an exclusive application cflock to prevent any other thread from accessing the scope until the modifications are complete.

As an aside, though it wouldn't completely eliminate the possibility of race conditions, using a separate variable for initialization, and assigning only when finished, would've reduced the window of opportunity for clashes:

 <cfloop ...> 
     <cfset local.someVariable[key] = ....>
 </cfloop>

 <cfset application.someVariable = local.someVariable>

Having said all of that, I agree you definitely don't want to be refreshing the application scope so frequently.

SOS
  • 6,430
  • 2
  • 11
  • 29
  • I think `applicationStop()` will cause the regular behavior of `onApplicationStart()` to fire, since it will stop the application and then cause it to restart normally. I'm not sure though. I'd need to test. – Shawn Dec 22 '18 at 17:29
  • Though the regular behavior *might* include other things besides just repopulating the application scope.... – SOS Dec 22 '18 at 18:04
  • I think `onApplicationStart()` isn't much more than a function. So calling it directly would just call whatever is inside the function. Whereas calling `applicationStop()` would actually stop the application and then the next call essentially restarts the application. So whatever magic happens before `onApplicationStart()` would still fire, and then `onApplicationStart()`. I think it should be thread-safe by stopping it and letting it restart itself. The fun of an app engine, right? :-) – Shawn Dec 23 '18 at 03:16
  • 1
    Yep, I was thinkiing something similar (surprise, surprise). I just meant, one should keep in mind doing it that way might trigger other tasks/magic beyond refreshing the app scope. That is not a problem, just something to be aware of i.e. that its probably doing more than calling onApplication start does – SOS Dec 23 '18 at 03:28