Потеря предметов в массивах Coldfusion
Это сводит меня с ума. Мы попытались создать оболочку memcached CF У нас есть такой компонент memcached.cfc:
<cfset this.m = arraynew(1)>
<cffunction name="init" access="public" output="false">
<cfif not isdefined("application.memcached")
....
<cfscript>
setup();
</cfscript>
...
<cfset application.memcached = this>
</cfif>
<cfreturn application.memcached>
</cffunction>
<cffunction name="setup" access="private" output="false">
<cftry>
<cfset this.m = arraynew(1)>
<cfloop from="1" to="#this.poolSize#" index="i">
<cfset this.m[i] = createClient()>
</cfloop>
<cflog application="no" file="memcached" text="Successfully set up #this.poolSize# new memcache clients">
<cfcatch>
<cflog application="no" file="memcached" text="Exception in setup() while setting up the pool: type: #cfcatch.type#, message: #cfcatch.message#, detail: #cfcatch.detail#">
</cfcatch>
</cftry>
</cffunction>
<cffunction name="createClient" access="private" output="false">
<cfset var AU = createObject("java", "net.spy.memcached.AddrUtil").init()>
<cfset var c = createObject("java", "net.spy.memcached.MemcachedClient").init(AU.getAddresses("127.0.0.1:11211"))>
<cfreturn c>
</cffunction>
<cffunction name="getCache" access="public" returntype="any" output="false">
<cfset idx = ceiling(rand() * 20)>
<cfreturn application.memcached.m[idx]>
</cffunction>
Странно то, что после запуска в течение 30 минут или около того, getCache начинает сбой, говорит, что в массиве application.memcached.m нет позиции в позиции idx.
Как это могло случиться? Используют ли массивы CF слабые ссылки или что-то в этом роде? Конечно, когда массив заполнен 20 клиентами, массив должен всегда оставаться заполненным?
Каждый новый клиент порождает новый поток, поэтому, как только мы теряем ссылку на клиента, теперь есть способ его закрыть, и этот поток живет там вечно, занимая память. Пожалуйста, чего мне не хватает?
3 ответа
Когда этот memcached CFC привыкнет? Каждый запрос? Отсутствие var scoping для переменных 'i' и 'idx' вполне может иметь к этому отношение. Вот пара статей, которые я написал, которые демонстрируют, почему это так важно.
http://duncan99.wordpress.com/2009/03/12/the-importance-of-var-scoping/
http://duncan99.wordpress.com/2009/03/16/the-importance-of-var-scoping-part-2/
Возможно, область вашего приложения будет удалена. Вы должны указать правильное время ожидания для этого. Вы также должны регистрировать это независимо от того, вызывается ли OnApplication или нет для целей отладки.
Ответ, вероятно, довольно прост - тот факт, что любое создание этого класса немедленно аннулирует массив в области приложения, делает этот класс довольно сложным для управления. Кроме того, хотя сам шпионский memcached драйвер ведет себя как одноэлементный, а массив (java.util.vector) является поточно-ориентированным, ничего другого в этой реализации нет, кроме области приложения, определенно не экземпляра cfc.
Предполагая, что вы можете исключить выходящее за пределы значение для idx в функции getCache() (что, я полагаю, вы уже сделали, если нет, бросить блок try/catch в функцию и сообщить, что такое idx, когда генерируется исключение), вы может устранить симптомы, фактически не устраняя причину, используя эксклюзивные cflocks с тем же именем вокруг конструктора и метода getCache(). Таким образом, даже если у вас есть случайные экземпляры вашего класса, вы никогда не сможете выбросить массив, когда что-то пытается к нему получить доступ, и вы не сможете попытаться получить к нему доступ, пока он создается заново., Это вовсе не оптимальное решение, и если вы испытываете высокий параллелизм, вы заметите небольшое увеличение времени отклика (довольно незначительное, но в зависимости от того, сколько запросов / сек вы обслуживаете, это может определенно повлиять на максимальную пропускную способность.