Указанный вами символ не является функцией - PullRequest
2 голосов
/ 01 сентября 2011

Ключевые моменты, прежде чем читать дальше

  1. Все переменные правильно изменены (вам придется мне доверять)
  2. Области действия не сбрасываются , пока происходят эти длительные процессы
  3. При сбросе метаданных для предположительно отсутствующего / недопустимого метода я получаю правильную информацию
  4. Есть только два места, где имя этого метода указано в приложении. Один раз, где он определен, и один раз, когда метод вызывается в коде ниже.

У меня очень странная прерывистая ошибка, которую я не могу отследить. Вот фон (они сильно обрезаны для упрощения публикации).

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) />

Итак, когда фид передается в функцию processXMLFile, он просматривает все элементы в файле. Файл канала может содержать 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 записей, или я могу получить небольшую порцию ошибок за один раз, и остальные процессы подачи работают нормально (из-за некоторой логики try / catch, предотвращающей выпадение всей вещи) ). В какой-то момент checkCustomerListing находился в совершенно другом объекте области сервера, и у меня никогда не было проблем. Я переместил его в FeedDAO и начал вызывать его через область действия Super, и именно тогда начались эти случайные ошибки.

ОБНОВЛЕНИЕ : У меня все правильно поменяно, я просто вырезал все это для краткости.

ОБНОВЛЕНИЕ СНОВА : Изменены комментарии к примеру кода, чтобы было ясно, что много вещей происходит до начала первого цикла, включая установку всех ЛОКАЛЬНЫХ переменных, которые будут использоваться в цикле.

Дополнительная информация о коде : Я должен отметить, что во всем нашем приложении есть только два места (тысячи и тысячи строк кода), где существует строка 'checkCustomerListing'. Один - где вызывается функция, а второй - где объявлена ​​функция. Других экземпляров строки checkCustomerListing нет нигде.

Обновление: 6 сентября 2011 г.

Я добавил дополнительную проверку ошибок, чтобы узнать, смогу ли я узнать, что приложение думает checkCustomerListing (спасибо Адаму и Райану). Вот мой новый оператор 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

Вся эта метаинформация точно правильна ... поэтому, если он может найти метаданные для функции, почему он не может найти саму функцию?

Ответы [ 4 ]

6 голосов
/ 01 сентября 2011

Это обычно возникает в результате отсутствия VARing, на что ссылались другие.Довольно часто у людей есть частная функция getStuff, и внутри них есть запрос getStuff.Если переменная не VARed, то результат запроса getStuff попадает в область видимости переменных CFC, которая перезаписывает функцию getStuff, поскольку она также находится в области видимости переменных.

Так что проверяйте использование checkCustomerListing для любого такого жепеременные с именами, которые не являются VARed (или не находятся в локальной области видимости)в ХФУ или в любых дополнительных или супер-ХФУ ...)

1 голос
/ 06 сентября 2011

Это может быть в вашем сокращенном коде, но вы проверяете, что local.invStruct.AcctID и local.invStruct.CustomerListingID оба существуют и имеют надлежащие типы?Иногда в Java «функция не существует» означает «сигнатура метода не существует».Я не уверен, когда CF проверяет типы данных, но если вы зацикливаетесь на одних и тех же двух переменных, возможно, вы используете ярлыки и не проверяете типы в более поздних циклах.случай.

1 голос
/ 01 сентября 2011

Почему вы делаете super.checkCustomerListing? Это можно сделать только в том случае, если вы переопределите функцию в своем сервисе и захотите запустить «родитель». Просто вызовите checkCustomerListing ().

0 голосов
/ 01 сентября 2011

Я видел это раньше, когда у вас есть объект, кэшированный в области, которая требует времени для запуска, и вы либо перезаписываете, либо удаляете объект в кэше. я предполагаю, что это то, что происходит, другое приложение что-то делает с объектом в кеше и заставляет другие приложения работать друг с другом.

хороший способ проверить это - скопировать объект, кэшированный в области видимости сервера, в локальную переменную, а затем использовать эту локальную переменную для запуска вашего процесса:

<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 (), которое скопирует все объекты, которые вы кэшируете, в область сервера в область приложения. единственная причина, по которой я вижу, что кто-либо когда-либо использовал область действия сервера, заключается в том, что вы хотите, чтобы все приложения на сервере совместно использовали одни и те же объекты. выполнение этого все еще позволит вашим приложениям использовать один и тот же код, но предотвратит случайное срабатывание других приложений друг над другом

...