The symbol you provided is not a function
Key points before reading further
- All variables are properly var'ed (you'll have to trust me)
- Scopes are not being reset while these long-running processes are happening
- When dumping the metadata for the supposedly missing/invalid method, I get the right information
- There are only two places where the name of this method are referenced in the application. Once where it's defined, and once were the method is called in the code below.
I have a very strange intermittent error that I can't seem to track down. Here's the background (these are severely trimmed down to simplify for posting).
FeedService.cfc:
<cfcomponent output="false" extends="FeedDAO">
<cffunction name="processXmlFile" access="public" output="false" returntype="struct">
<cfset Var local = StructNew() />
/***************************************
THE VARIABLES ARE ALL VAR'D - PROMISE!!!
Lots of other stuff goes on in here to get the ultimate set of XML nodes to loop through
*****************************************/
<cfloop from="1" to="#ArrayLen(local.arrChannels)#" index="local.currentChannelItem">
... Lots of XML parsing and stuff and things going on here ...
<cfset LOCAL.invCheck = checkCustomerListing(
Acct_ID = local.invStruct.AcctID
, CustomerListingID = local.invStruct.CustomerListingID
) />
... Lots more stuff going on here ...
</cfloop>
</cffunction>
</cfcomponent>
FeedDAO:
<cfcomponent output="false">
<cffunction name="checkCustomerListing" access="public" output="false" returntype="numeric" hint="Returns the numeric inventory ID for an existing inventory listing, or 0 if the listing doesn't exist.">
<cfargument name="Acct_ID" type="numeric" required="true" hint="" />
<cfargument name="CustomerListingID" type="string" required="true" hint="" />
<cfset var rs = "">
<cfquery name="rs" datasource="#Variables.DSNs.Primary#">
SELECT ID FROM TheTable
WHERE
Acct_ID = <cfqueryparam cfsqltype="cf_sql_integer" value="#Arguments.Acct_ID#" />
AND Customer_Listing_ID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Arguments.CustomerListingID#" />
</cfquery>
<cfif rs.RecordCount>
<cfreturn rs.Inv_ID />
<cfelse>
<cfreturn 0 />
</cfif>
</cffunction>
</cfcomponent>
I'm calling the initial function like so:
<cfset processStruct = Server.FeedService.processXmlF开发者_如何学Pythonile(filePath) />
So, when a feed gets submitted to the processXMLFile function, it looks through all of the items in the file. A feed file may have 10, 100, or even 1000 entries. I get occasional error messages like this while a file is getting processed:
[struct]
Detail: The symbol you provided checkCustomerListing is not the name of a function.
Message: Entity has incorrect type for being called as a function.
StackTrace: coldfusion.runtime.CfJspPage$UninvocableEntityException: Entity has incorrect type for being called as a function.
at coldfusion.runtime.CfJspPage._invokeUDF(CfJspPage.java:2441)
at coldfusion.runtime.SuperScope.invoke(SuperScope.java:18)
at coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2222)
More stack dump information
Type: Application
symbolName: checkCustomerListing
[object of coldfusion.runtime.CfJspPage$UninvocableEntityException]
Class Name: coldfusion.runtime.CfJspPage$UninvocableEntityException
Fields:
java.lang.String symbolName: checkCustomerListing
Parent Class: [object of coldfusion.runtime.ApplicationException]
Class Name: coldfusion.runtime.ApplicationException
Parent Class: [object of coldfusion.runtime.NeoException]
Class Name: coldfusion.runtime.NeoException
Methods:
findAdvancedCFTarget(coldfusion.runtime.AdvancedCFException, java.lang.String[]) returns int
findCustomTarget(coldfusion.runtime.CustomException, java.lang.String[]) returns int
findThrowableTarget(java.lang.Throwable, java.lang.String[]) returns int
getDetail() returns java.lang.String
getLocalizedMessage() returns java.lang.String
getMessage() returns java.lang.String
getRootCause() returns java.lang.Throwable
getString(java.lang.Throwable, java.lang.String, java.util.Locale) returns java.lang.String
getType() returns java.lang.String
setLocale(java.util.Locale) returns void
unwrap(java.lang.Throwable) returns java.lang.Throwable
Parent Class: [object of java.lang.RuntimeException]
Class Name: java.lang.RuntimeException
Parent Class: [object of java.lang.Exception]
Class Name: java.lang.Exception
Parent Class: [object of java.lang.Throwable]
Class Name: java.lang.Throwable
Methods:
fillInStackTrace() returns java.lang.Throwable
getCause() returns java.lang.Throwable
getLocalizedMessage() returns java.lang.String
getMessage() returns java.lang.String
getStackTrace() returns java.lang.StackTraceElement[]
initCause(java.lang.Throwable) returns java.lang.Throwable
printStackTrace(java.io.PrintWriter) returns void
printStackTrace(java.io.PrintStream) returns void
printStackTrace() returns void
setStackTrace(java.lang.StackTraceElement[]) returns void
toString() returns java.lang.String
I may get one error in 1000 entries, or I may get a small batch of errors at one time, and the rest of the feed processes just fine (due to some try/catch logic to prevent the entire thing from crapping out). At one point, the checkCustomerListing
was in a completely different Server scoped object, and I never had a problem. I moved it into the FeedDAO
and started calling it via the Super scope, and that's when these intermittent errors began.
UPDATE: I have everything properly var'ed, I just chopped it all out for the sake of brevity.
UPDATE AGAIN: Changed code sample comments to make it clear that there is a lot of stuff going on before the first loop begins, including setting all LOCAL variables that will be used in the loop.
More Code Information:
I should note that there are only two places in our entire application (thousands upon thousands of lines of code) where the string 'checkCustomerListing' exists. One is where the function is called, and two is where the function is declared. There are no other instances of the string checkCustomerListing
anywhere.
Update: 6 September, 2011
I added some additional error checking to see if I could find out what the app thought checkCustomerListing
was (thanks Adam and Ryan). Here's my new try/catch statement:
<cfcatch type="any">
<cfset local.tmpError.cfcatch = cfcatch>
<cfif isDefined("checkCustomerListing")>
<cfset local.tmpError.customerListing = checkCustomerListing />
<cfset local.tmpError.customerListingMeta = getMetaData(checkCustomerListing) />
<cfelse>
<cfset local.tmpError.customerListing = "Checkcustomerlisting is not defined" />
</cfif>
<cfset Server.Utilities.Errors.emailCaughtError(local.tmpError)>
</cfcatch>
So I got an error this morning, and in the email I received, there is no customerListing
node in the dump, but there is a meta node:
CUSTOMERLISTINGMETA:
[struct]
ACCESS: public
HINT: Returns the numeric inventory ID for an existing inventory listing, or 0 if the listing doesn't exist.
NAME: checkCustomerListing
OUTPUT: false
PARAMETERS:
[array]
1) [struct]
HINT: [empty string]
NAME: Acct_ID
REQUIRED: true
TYPE: numeric
2) [struct]
HINT: [empty string]
NAME: CustomerListingID
REQUIRED: true
TYPE: string
RETURNTYPE: numeric
All of that meta information is exactly correct... so if it can find the metadata for the function, why can't it find the function itself?
This usually crops up as a result of lack of VARing as others have alluded to. Quite often people have a private function called "getStuff" and within that they have a query called "getStuff". If the variable isn't VARed, then the getStuff query result goes into the CFC's variables scope, which will overwrite the function getStuff because that also resides in the variables scope.
So check your usage of checkCustomerListing for any same-named variables that aren't VARed (or in the local scope).
(and note that the checkCustomerListing variables don't need to be within the same method for this to happen... it could be anywhere in the CFC or any extending or super CFCs...)
Why are you doing super.checkCustomerListing? You would only do that if you overrode the function in your service and wanted to run the 'parent'. Just call checkCustomerListing().
It may be in your abridged code but are you validating that local.invStruct.AcctID and local.invStruct.CustomerListingID both exist and are of the proper types? Sometimes in Java "function doesn't exist" means "method signature doesn't exist". I am not sure when CF validates datatypes but if you are looping over the same two variables if might be shortcutting and not validating the types in later loops.
Might also toss a val() on the return value just in case.
i've seen this before when you have an object cached in a scope that is taking a while to run and you either overwrite or remove the object in the cache. my guess is this is what is happening, another application is doing something to the object in the cache and it's casuing the other applications to trip over each other.
a good way to test this is to duplicate the object cached in the server scope to a local variable and then use that local variable to run your process:
<cfset _feedservice = duplicate(Server.FeedService)>
<cfset processStruct = _feedservice.processXmlFile(filePath) />
now even if the object in the server scope gets overwritten or removed, you still have a copy of the original object that your process will use. it also won't be a bad idea to use locks around the above code:
<cflock scope="server" timeout="5" type="readonly">
<cfset _feedservice = duplicate(Server.FeedService)>
<cfset processStruct = _feedservice.processXmlFile(filePath) />
</cflock>
now personally an even better practice (in my opinion) would be to add something to your onApplicationOnStart() event that will copy all the objects that you are caching to the server scope into the application scope. the only reason i can see anyone ever using the server scope is because you want all the applications on the server sharing the same objects. doing this will still allow your applications to share the same code, but will prevent other applications from accidentally tripping over each other
精彩评论