Возможное состояние гонки при создании структур в ColdFusion

Я видел периодически возникающие ошибки в нескольких системах, над которыми я работал, при использовании одной и той же методологии (не того же кода), что заставило меня поверить, что проблема может быть связана с созданием и использованием структур в одном и том же запросе. Мне интересно, возможно ли, что есть состояние гонки?

Сценарий таков: мы в системе электронной коммерции просматриваем продукт или, в некоторых случаях, список продуктов. Рассматриваемый код предназначен для возврата изображений, связанных с каждым продуктом, в структуру, которую мы можем использовать для отображения указанных изображений.

В начале запроса код ищет записи базы данных, связанные с рассматриваемым элементом. Эти записи представляют собой изображения продуктов. Эти записи возвращаются в одном вызове CFQuery (или, точнее, вызове функции, которая возвращает результаты вызова CFQuery в форме структуры, содержащей различную информацию).

Затем код перебирает предоставленную структуру изображения и добавляет различную информацию в локальную структуру. Позже в запросе мы используем данные в структуре для отображения изображений в наших тегах <img>. Мы также заполняем тег <img> атрибутами data- для использования с JavaScript.

В случае, если какое-либо конкретное изображение не было правильно возвращено запросом — обычно из-за отсутствия физического файла — мы используем общий образ-заполнитель. Это делается путем помещения создания структуры в блок try/catch.

Важно: это работает.

Однако происходит то, что очень периодически, когда мы обращаемся к узлу в созданной нами структуре, мы обнаруживаем, что он не существует, и CF выдает ошибку - это происходит примерно в 1% случаев. и перезагрузка той же страницы, все будет работать отлично.

У меня была одна и та же проблема в нескольких системах, на нескольких серверах, в разных версиях ColdFusion (в частности, 8 и 10) и с использованием совершенно другого кода для достижения аналогичных результатов. Первая система, в которой я увидел эту проблему, фактически использовала FileExists для проверки доступности файла изображения, и поэтому я подумал, что проблема, вероятно, была вызвана узким местом файловой системы - я пробовал много способов обойти это и в конечном итоге полностью устранил ее в новая система - но проблема осталась.

Единственное, о чем я могу думать, это то, что при создании структуры и последующем использовании этой структуры в том же запросе существует вероятность возникновения состояния гонки; при этом я ссылаюсь на узел в структуре до того, как он будет создан. Однако я не использую здесь многопоточность, поэтому я не понимаю, как это возможно... У меня нет других идей.

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

<!--- Get product images --->
<cfset Local.stProductImages = Application.cfcParts.getPartImages(
        l_iItemID = Arguments.pid
) />


<!--- Loop through images --->
<cfloop list="#ListSort(structKeyList(Local.stProductImages['item_' & Arguments.pid]), 'text')#" index="i">
    <cftry>
        <cfset Local['ImageURL_' & i & '_Large']    = Local.stProductImages['item_' & Local.arguments.pid][i].large_watermarked.URL />
        <cfcatch>
            <cfset Local['ImageURL_' & i & '_Large']    = Application.com.Images.getMissingImages().large />
        </cfcatch>
    </cftry>                        
    <cftry>
        <cfset Local['ImageURL_' & i & '_Med']      = Local.stProductImages['item_' & Local.arguments.pid][i].med.URL />
        <cfcatch>
            <cfset Local['ImageURL_' & i & '_Med']      = Application.com.Images.getMissingImages().med />
        </cfcatch>
    </cftry>                        
    <cftry>
        <cfset Local['ImageURL_' & i & '_Small']        = Local.stProductImages['item_' & Local.arguments.pid][i].small.URL />
        <cfcatch>
            <cfset Local['ImageURL_' & i & '_Small']        = Application.com.Images.getMissingImages().small />
        </cfcatch>
    </cftry>                        

    <img class          = "altProdImg<cfif i EQ 'image_03'> endImage</cfif>" 
        src             = "#Local['ImageURL_' & i & '_Small']#" 
        image           = "#i#" 
        alt             = ""
        data-imgsmall   = "#Local['ImageURL_' & i & '_Small']#"
        data-imgmed     = "#Local['ImageURL_' & i & '_Med']#"
        data-imglarge   = "#Local['ImageURL_' & i & '_Large']#"
        data-imgnum     = "#i#"
        data-pid        = "#Arguments.pid#"
    />
</cfloop>

Ошибка возникает в теге <img> при ссылке на узел, созданный в предыдущем коде — что-то вроде:

Элемент ImageURL_image_02_Large не определен в объекте Java класса типа coldfusion.runtime.LocalScope.

Но только изредка... Я перезагружаю и каждый раз все работает отлично.

Итак... извините за эпическую длину вопроса, но может ли кто-нибудь увидеть, как это могло произойти?


person Gary Stanton    schedule 08.11.2013    source источник
comment
varscoper.riaforge.org   -  person Peter Boughton    schedule 08.11.2013
comment
Не уверен, что я с вами, Питер - я думал, что область видимости var предназначена для функций? Вызываемые функции (Application.cfcParts.getPartImages и Application.com.Images.getMissingImages) корректно имеют varscope - есть ли что-то, что я должен делать и внутри .cfm??   -  person Gary Stanton    schedule 08.11.2013
comment
Кроме того, просто запустил VarScoper для рассматриваемого файла, и он ничего не вернул! Не могу быть уверен, что я использую его правильно, никогда не использовал его раньше.   -  person Gary Stanton    schedule 08.11.2013
comment
Вы уверены, что код не вызывается из функции? Описанное вами поведение является признаком того, что область видимости не var, и ошибка конкретно указывает на локальную область (которая существует только в функциях). Кроме того, вы имеете в виду Arguments.pid?   -  person Peter Boughton    schedule 08.11.2013
comment
вы используете область local, что подразумевает, что этот код находится внутри функции, так как это все, для чего предназначена локальная область   -  person duncan    schedule 08.11.2013
comment
(VarScoper не идеален и не может обнаруживать переменные с незаданной областью во включенных файлах, т. е. <cffunction...><cfinclude .../></cffunction>, что делают некоторые фреймворки.)   -  person Peter Boughton    schedule 08.11.2013
comment
да, давайте посмотрим код в getMissingImages и getPartImages. Также вы вызываете getMissingImages() три раза. Не могли бы вы вызвать его один раз, сохранить результаты в одной структуре, а затем ссылаться на структуру small/med/large по мере необходимости?   -  person duncan    schedule 08.11.2013
comment
Это может быть так же просто исправить, как использовать index="local.i" в теге cfloop (вам нужна только область видимости при записи переменной).   -  person Peter Boughton    schedule 08.11.2013
comment
Это определенно не внутри функции, нет... Существует переменная области «Аргументы» — к сожалению, это устаревшая система, и я просто работаю с переменными, которые мне дали! Что касается локальной области, я всегда использовал ее внутри файлов .cfm, а также функций. Это просто удобный способ группировки переменных, которые я создаю. Возможно, мне следует вместо этого использовать «Переменные», но раньше это никогда не вызывало проблем... Если есть причина не делать этого, я хотел бы узнать больше.   -  person Gary Stanton    schedule 08.11.2013
comment
getMissingImages просто возвращает частную структуру в компоненте. Когда он создается, я передаю расположение отсутствующих файлов изображений в виде структуры, которая хранится в области частных переменных компонента. Буквально все функции содержат следующее: <cfreturn Variables.MissingImages /> Конечно, я мог бы просто вызвать это один раз и сохранить результат, но учитывая, что никакой обработки не требуется, я не думаю, что будут накладные расходы. getPartImages возвращает результат другой функции, работающей с изображениями. Я уверен, что все в правильном масштабе. Выложу, если потребуется.   -  person Gary Stanton    schedule 08.11.2013
comment
@PeterBoughton - я попробую локальную область в цикле - может потребоваться некоторое время, чтобы сообщить об этом, поскольку проблема очень прерывистая.   -  person Gary Stanton    schedule 08.11.2013
comment
Да, начиная с CF8 область local — это имя, в которое с помощью ключевого слова var помещаются переменные (на самом деле это не так просто, но достаточно близко). Так что я бы, наверное, посоветовал избегать использования только local в качестве обычной переменной, чтобы избежать путаницы. (И я бы тоже починил этот Arguments.)   -  person Peter Boughton    schedule 08.11.2013
comment
Относительно простой способ проверить, находитесь ли вы в функции, не просматривая код: <cfthrow message="where am i?" /> затем проверьте трассировку стека - если вы видите что-то вроде coldfusion.runtime.UDFMethod или $funcSTUFF.runFunction(filename:line), значит, вы находитесь внутри одной из них.   -  person Peter Boughton    schedule 08.11.2013
comment
Да, и для возможного способа вызвать ошибку попробуйте инструмент нагрузочного тестирования, такой как JMeter - может помочь заставьте это происходить чаще (и, таким образом, помогите проверить, когда оно исправлено/уменьшено).   -  person Peter Boughton    schedule 08.11.2013
comment
Что ж, при написании функций я обычно использую <cfset var Local = {} /> вверху и после этого сохраняю все внутри локальной области видимости... Я почти уверен, что это был беннаделизм и, таким образом, совершенно безошибочен. ;) Это больше не хорошая практика? Увы, я не могу исправить переменную Arguments, в этой системе чертовски огромный путь запроса, и мне пришлось бы изменить его в таком количестве файлов, о которых он даже не думает. Я не должен быть на работе, но ведь это действительно ужасная система, работающая через Fusebox, так что кто знает? Я проверю. Ваше здоровье.   -  person Gary Stanton    schedule 08.11.2013
comment
Ага... Кажется, я действительно нахожусь в функции... .cfm, над которым я работаю, является шаблоном, включенным в функцию (который запускается шаблоном, включенным в функцию в функция в функции в функции в... Я ненавижу эту систему). Итак, я думаю, что мы на что-то с этим. Бьюсь об заклад, одна из этих функций не имеет локального varscope...   -  person Gary Stanton    schedule 08.11.2013
comment
Внутри функции, если вам нужно поддерживать старые двигатели (CF7/OBD/и т. д.), тогда <cfset var Local = {} /> в порядке (есть некоторые незначительные проблемы). Если вы работаете на современных двигателях, в этом нет необходимости. Я имел в виду не использовать его вне функций.   -  person Peter Boughton    schedule 08.11.2013
comment
Если большинство функций начинаются с var local, это регулярное выражение может помочь найти куплет: <cffunction[^>]+>(?:\s*<cfargument[^>]+>)*(?!\s*<cfset\s+var\s+local\s*=\s*\{) - не идеально, но, возможно, стоит попробовать, если оно быстро найдет его. :)   -  person Peter Boughton    schedule 08.11.2013
comment
Моих навыков регулярных выражений не существует, поэтому я не уверен, что это пытается сделать, но он возвращает сотни функций, включая те, которые имеют varscoped. Спасибо, в любом случае! Система была написана для CF8 и теперь находится на CF10, но я всегда считал, что это не помешает. Однако я всегда использовал свою собственную «локальную» область вне функций. Просто казалось, что это правильное место, чтобы положить вещи. Мне не нравится идея изменить это в сотнях тысяч файлов, в которых оно используется!!! Это действительно проблема? Любые ссылки, по которым я могу перейти для объяснения этого?   -  person Gary Stanton    schedule 08.11.2013
comment
Нет, не настолько большая проблема, чтобы все менять, просто лучше не использовать встроенные имена областей для переменных без области/корневого уровня, так как это менее запутанно и позволяет избежать потенциальных конфликтов с реальной областью (например, в функции с <cfargument name="url" ... /> вы не могу добраться до области url.) Так что, возможно, используйте что-то еще в будущем, но, вероятно, не нужно беспокоиться о том, чтобы вернуться и изменить старые вещи.   -  person Peter Boughton    schedule 08.11.2013
comment
Чтобы было ясно, я не говорю об использовании «Local» в качестве имени переменной... Я бы никогда этого не сделал!! Я просто помещаю все в область Local, а иногда и в область Request, если это кажется более подходящим... Тогда другие люди просто используют область видимости, используя Variables?   -  person Gary Stanton    schedule 08.11.2013
comment
Когда вы говорите... Однако я всегда использовал свою собственную "локальную" область видимости вне функций. - вне функций нет локальной области видимости, поэтому используется локальная область в качестве имени переменной для структуры. Некоторые люди используют loc как короткое имя, которое отличается от local, но все же относительно очевидно (конечно, некоторые люди ненавидят сокращения в коде, поэтому не согласятся с этим).   -  person Peter Boughton    schedule 08.11.2013
comment
Ах, да, я понимаю, что вы говорите... Итак, «моя собственная локальная область» на самом деле является переменной без области видимости, называемой «Локальная». Имеет смысл, когда вы пишете это. Баггер. Ну, всегда учишься, да? Десять чертовых лет я этим занимаюсь!   -  person Gary Stanton    schedule 08.11.2013
comment
Итак, я обновил цикл, чтобы использовать Local.i, и через несколько часов у меня не было ошибок... что не означает, что проблема решена, но это многообещающе. Дело в том, что, как обсуждалось ранее, я на самом деле не рассматриваю i, помещая его в локальную область, поскольку локальная область вообще не является областью! Итак, почему это должно работать?   -  person Gary Stanton    schedule 08.11.2013
comment
Что ж, после нескольких дней отсутствия ошибок я убежден, что проблема с областью действия действительно была виновником - кажется, что добавление «Local» к индексу цикла решило проблему. @PeterBoughton - если вы хотите отправить это как ответ, я отмечу его принятым за виртуальную славу ... и спасибо за помощь! ;)   -  person Gary Stanton    schedule 11.11.2013


Ответы (1)


Ответ из комментариев...

Описанное вами поведение является признаком отсутствия области видимости var, поэтому исправить ее может быть так же просто, как использовать index="local.i" в теге cfloop (вам нужна область видимости только при записи переменной).


Примечание. Относительно простой способ проверить, находитесь ли вы в функции, не заглядывая в код, — выдать ошибку (например, <cfthrow message="where am i?" />), а затем проверить трассировку стека. видеть такие вещи, как coldfusion.runtime.UDFMethod или $funcSTUFF.runFunction(filename:line), вы знаете, что находитесь внутри функции (даже если шаблон, в котором вы находитесь, не показывает никаких признаков этого).

person Peter Boughton    schedule 12.11.2013