I'm running into an issue that only seems to affect our production server and without any apparent rhyme or reason. Essentially, we're getting the following error (I'm going to use dummy names to illustrate the point):
Message: Neither the method someFunction was found in component Components.services.SomeComponent nor was there any default method with this name present in any of the implementing interface.
This happens at a few different lines in the codebase but once it's been thrown, it will never get past that point again until clearing the Component Cache in CFADMIN. Here's the kicker: the offending line in the code looks like this:
<cfset var a = createObject("Components.services.app.ComponentA").someFunction() >
It seems like the createObject call to create ComponentA is instead returning an instance of SomeComponent. I've tried the following:
- The CreateObject calls in this section had been using dynamically created strings for the component path... I thought maybe something was getting polluted so now
Components.services.app.ComponentA,Components.services.app.ComponentB, etc... are all hard-coded - I tried using the
newsyntax instead ofcreateObject - I thought maybe there was something wrong with the path to where the Component Cache was getting confused, so I created a mapping to
./Components/services/appcalled (for instance) "app" so that I could create the objects likenew app.ComponentA()instead ofnew Components.services.app.ComponentA
Nothing seems to help -- none of this is reproducible in our UAT or anyone's dev environments and it's intermittent in production, but, again, once it's been thrown that server is done. Clearing Component Cache in CFADMIN temporarily fixes it until someone will randomly throw it again hours later.
Some additional caveats:
- As we've moved and shuffled things around trying to find the cause of this problem, the specific line numbers and components seem to change but the behavior is always the same -
new ComponentC()is instead creatingsomeComponent...new ComponentA()is instead creatingsomeOtherComponent - This is only happening in one specific section of our codebase that uses a lot of object inheritance compared to the rest of our code. We've combed through to make sure there aren't any circular references or anything like that, and the evil components (
someComponent,someOtherComponent) are CFC's that live outside this directory - The fact that clearing the Component Cache seems to resolve this really makes me suspicious of the Component Cache... I just don't know enough under the hood with CF to have any inkling why the cache may return an instance of a different object than the one it's calling
Next steps (none of these are ideal):
- Disabling the component cache altogether, don't want to take the performance hit
- Adding some ridiculous code to clear the component cache programmatically if an invalid method name error is thrown
Is there some way to granularly exclude certain CFC's from being retrieved from the Component Cache and force them to be re-evaluated when calling createObject()?
I've seen this behavior before when the component is using a path that has an Application mapping. I've seen this happen in a few different scenarios, but the most common scenario was like this:
In your Application.cfc, there's a mapping to your components that uses a relative path. Something like:
As long as the application is always initialized from the same folder as the
Application.cfcthen this works fine. However, if the application is initialized from a subfolder, then theComponentsmapping no longer points to the expected folder.If you need to use a relative path for a mapping, you can avoid this by doing something like:
That should force the mapping to always use the same physical path folder, even when called from a subfolder.
Another scenario in which I've seen this happen is in a shared environment where there are multiple Applications with the same name.
If you have multiple instances of a website running that are using the same Application name in your
Application.cfc, then the first website that is initialized ends up sharing it's mappings with the other application. If the applications are different, this can lead to components not being found.Hopefully one of these two scenarios gets you on the right track to resolving your issue!