Я видел периодически возникающие ошибки в нескольких системах, над которыми я работал, при использовании одной и той же методологии (не того же кода), что заставило меня поверить, что проблема может быть связана с созданием и использованием структур в одном и том же запросе. Мне интересно, возможно ли, что есть состояние гонки?
Сценарий таков: мы в системе электронной коммерции просматриваем продукт или, в некоторых случаях, список продуктов. Рассматриваемый код предназначен для возврата изображений, связанных с каждым продуктом, в структуру, которую мы можем использовать для отображения указанных изображений.
В начале запроса код ищет записи базы данных, связанные с рассматриваемым элементом. Эти записи представляют собой изображения продуктов. Эти записи возвращаются в одном вызове 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.
Но только изредка... Я перезагружаю и каждый раз все работает отлично.
Итак... извините за эпическую длину вопроса, но может ли кто-нибудь увидеть, как это могло произойти?
Arguments.pid
? - person Peter Boughton   schedule 08.11.2013local
, что подразумевает, что этот код находится внутри функции, так как это все, для чего предназначена локальная область - person duncan   schedule 08.11.2013<cffunction...><cfinclude .../></cffunction>
, что делают некоторые фреймворки.) - person Peter Boughton   schedule 08.11.2013index="local.i"
в теге cfloop (вам нужна только область видимости при записи переменной). - person Peter Boughton   schedule 08.11.2013getMissingImages
просто возвращает частную структуру в компоненте. Когда он создается, я передаю расположение отсутствующих файлов изображений в виде структуры, которая хранится в области частных переменных компонента. Буквально все функции содержат следующее:<cfreturn Variables.MissingImages />
Конечно, я мог бы просто вызвать это один раз и сохранить результат, но учитывая, что никакой обработки не требуется, я не думаю, что будут накладные расходы.getPartImages
возвращает результат другой функции, работающей с изображениями. Я уверен, что все в правильном масштабе. Выложу, если потребуется. - person Gary Stanton   schedule 08.11.2013local
— это имя, в которое с помощью ключевого словаvar
помещаются переменные (на самом деле это не так просто, но достаточно близко). Так что я бы, наверное, посоветовал избегать использования толькоlocal
в качестве обычной переменной, чтобы избежать путаницы. (И я бы тоже починил этотArguments
.) - person Peter Boughton   schedule 08.11.2013<cfthrow message="where am i?" />
затем проверьте трассировку стека - если вы видите что-то вродеcoldfusion.runtime.UDFMethod
или$funcSTUFF.runFunction(filename:line)
, значит, вы находитесь внутри одной из них. - person Peter Boughton   schedule 08.11.2013<cfset var Local = {} />
вверху и после этого сохраняю все внутри локальной области видимости... Я почти уверен, что это был беннаделизм и, таким образом, совершенно безошибочен. ;) Это больше не хорошая практика? Увы, я не могу исправить переменную Arguments, в этой системе чертовски огромный путь запроса, и мне пришлось бы изменить его в таком количестве файлов, о которых он даже не думает. Я не должен быть на работе, но ведь это действительно ужасная система, работающая через Fusebox, так что кто знает? Я проверю. Ваше здоровье. - person Gary Stanton   schedule 08.11.2013<cfset var Local = {} />
в порядке (есть некоторые незначительные проблемы). Если вы работаете на современных двигателях, в этом нет необходимости. Я имел в виду не использовать его вне функций. - person Peter Boughton   schedule 08.11.2013var local
, это регулярное выражение может помочь найти куплет:<cffunction[^>]+>(?:\s*<cfargument[^>]+>)*(?!\s*<cfset\s+var\s+local\s*=\s*\{)
- не идеально, но, возможно, стоит попробовать, если оно быстро найдет его. :) - person Peter Boughton   schedule 08.11.2013<cfargument name="url" ... />
вы не могу добраться до областиurl
.) Так что, возможно, используйте что-то еще в будущем, но, вероятно, не нужно беспокоиться о том, чтобы вернуться и изменить старые вещи. - person Peter Boughton   schedule 08.11.2013Local
, а иногда и в областьRequest
, если это кажется более подходящим... Тогда другие люди просто используют область видимости, используяVariables
? - person Gary Stanton   schedule 08.11.2013loc
как короткое имя, которое отличается отlocal
, но все же относительно очевидно (конечно, некоторые люди ненавидят сокращения в коде, поэтому не согласятся с этим). - person Peter Boughton   schedule 08.11.2013Local.i
, и через несколько часов у меня не было ошибок... что не означает, что проблема решена, но это многообещающе. Дело в том, что, как обсуждалось ранее, я на самом деле не рассматриваюi
, помещая его в локальную область, поскольку локальная область вообще не является областью! Итак, почему это должно работать? - person Gary Stanton   schedule 08.11.2013