进一步阅读之前的要点
我有一个非常奇怪的间歇性错误,我似乎无法追查。这是背景(这些都被严格修剪以简化发布)。
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>
我正在调用这样的初始函数:
<cfset processStruct = Server.FeedService.processXmlFile(filePath) />
因此,当Feed被提交到processXMLFile函数时,它会查看文件中的所有项目。 Feed文件可能包含10个,100个甚至1000个条目。在文件处理过程中,偶尔会收到类似的错误消息:
[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)
更多堆栈转储信息
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
我可能会在1000个条目中出现一个错误,或者我可能同时收到一小批错误,其余的Feed进程也很好(由于一些try / catch逻辑可以防止整个东西出现问题)。有一次,checkCustomerListing
处于完全不同的服务器作用域对象中,我从来没有遇到过问题。我把它移到FeedDAO
并开始通过超级范围调用它,这就是这些间歇性错误开始的时候。
更新:我有一切正确的变化,我只是为了简洁而把它全部切掉了。
再次更新:更改了代码示例注释,以明确在第一个循环开始之前存在很多的内容,包括设置所有LOCAL变量在循环中使用。
更多代码信息:
我应该注意,我们的整个应用程序中只有两个位置(成千上万行代码),其中存在字符串'checkCustomerListing'。一个是调用函数的地方,两个是声明函数的地方。任何地方都没有字符串checkCustomerListing
的其他实例。
更新:2011年9月6日
我添加了一些额外的错误检查,看看我是否能找到应用程序认为checkCustomerListing
的内容(感谢Adam和Ryan)。这是我的新try / catch语句:
<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>
所以我今天早上收到错误,在收到的电子邮件中,转储中没有customerListing
节点,但有一个元节点:
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
所有这些元信息都完全正确...所以如果它能找到函数的元数据,为什么它找不到函数呢?
答案 0 :(得分:6)
这通常由于缺乏VARing而出现,正如其他人所暗示的那样。通常人们都有一个名为“getStuff”的私有函数,并且在其中有一个名为“getStuff”的查询。如果变量不是VARed,那么getStuff查询结果将进入CFC的变量范围,这将覆盖函数getStuff,因为它也位于变量范围内。
因此,请检查checkCustomerListing对任何非VARed(或在本地范围内)的同名变量的使用情况。
(并注意checkCustomerListing变量不需要在同一方法中发生......它可能在CFC中的任何地方或任何扩展或超级CFC ......)
答案 1 :(得分:1)
你为什么要做super.checkCustomerListing?如果您覆盖服务中的功能并希望运行“父”,则只会这样做。只需调用checkCustomerListing()。
答案 2 :(得分:1)
它可能在您的删节代码中,但您是否验证local.invStruct.AcctID和local.invStruct.CustomerListingID都存在且属于正确的类型?有时在Java中“功能不存在”意味着“方法签名不存在”。我不确定CF何时验证数据类型,但如果您正在循环使用相同的两个变量,则可能是快捷方式而不是在后续循环中验证类型。
也可以在返回值上抛出val()以防万一。
答案 3 :(得分:0)
我之前看到过这种情况,当你有一个对象缓存在一个需要一段时间才能运行的作用域中时,你要么覆盖或删除缓存中的对象。我的猜测是这就是正在发生的事情,另一个应用程序正在对缓存中的对象做一些事情,并且它正在让其他应用程序相互绊倒。
测试它的一个好方法是将服务器作用域中缓存的对象复制到局部变量,然后使用该局部变量来运行您的进程:
<cfset _feedservice = duplicate(Server.FeedService)>
<cfset processStruct = _feedservice.processXmlFile(filePath) />
现在,即使服务器范围中的对象被覆盖或删除,您仍然拥有进程将使用的原始对象的副本。围绕上面的代码使用锁也不是一个坏主意:
<cflock scope="server" timeout="5" type="readonly">
<cfset _feedservice = duplicate(Server.FeedService)>
<cfset processStruct = _feedservice.processXmlFile(filePath) />
</cflock>
现在个人更好的做法(在我看来)是在onApplicationOnStart()事件中添加一些东西,它会将你正在缓存的所有对象复制到服务器范围到应用程序范围。我可以看到任何人使用服务器范围的唯一原因是因为您希望服务器上的所有应用程序共享相同的对象。这样做仍然允许您的应用程序共享相同的代码,但会阻止其他应用程序意外地相互绊倒