【发布时间】:2014-04-04 12:21:21
【问题描述】:
我需要在普通用户会话中运行某些 ColdFusion 代码块(例如:用户单击打印并生成 PDF)。该网页是交互式的,用户可以立即获得 PDF。
但我还需要在一个循环中多次运行相同的代码块(超过 1000 次迭代)。为此,我们告诉用户他们将在完成后收到一封电子邮件。我生成了一个低优先级的<cfthread> 并循环了相同的代码。问题是正在运行的代码严重依赖会话范围内的变量。因此,如果用户退出,线程会在遇到会话 var 时出错并终止。对于有问题的代码,我知道我可以将变量更改为不使用会话范围,然后线程将完成没有问题,但我们无法更改该代码。所以,我在几年前尝试了一种可行的方法,但我从来没有对此感觉良好,并且想知道是否有人能想到更好的方法。这就是黑客...
<cfapplication name="backgroundThread" sessionTimeout="#CreateTimeSpan(0, 0, 600, 0)#" sessionManagement="Yes">
<!--- Duplicate the entire session structure --->
<cflock scope="session" timeout="30" type="Exclusive">
<cfloop collection="#this.session#" item="session_element">
<cfset new_session_element = evaluate("this.session." & "#session_element#")>
<cfset "session.#session_element#" = new_session_element>
</cfloop>
</cflock>
<cfthread action="run" priority="low" name="#this.threadid#" session=session>
<!---
Normal code can be included here and it will run.
Even if the user who initiated the background process signs out.
--->
所以基本上我创建了一个全新的应用程序/会话,然后将所有会话变量复制到这个新的应用程序/会话。所以如果用户退出它不会对后台进程产生影响,需要会话变量的代码仍然会运行。
这已经工作了很长时间。偶尔我会研究它,但还没有找到更好的方法。在这样的应用程序中创建应用程序对我来说似乎不合适。有没有其他方法可以不使用使用<cfapplication> 标签生成新会话?
我考虑过调用application.cfc->onSessionStart,但这就是 Adobe 所说的:如果您明确调用此方法,ColdFusion 不会启动会话。我只需要生成一个新会话的能力,分开从当前用户,然后将他的大部分会话变量复制到它。
2014 年 2 月 24 日更新:我尝试了这个建议,但它仍然对我不起作用(测试是在 CF10 盒子上完成的)...
<cfthread action="run" name="testingSession" session="#session#" priority="LOW">
<cfset form.session = session> <!--- add this dirty trick --->
<cftry>
<cfloop from="1" to="200" index="i">
<cfscript>sleep(3000);</cfscript>
<cfquery name="q1" datasource="#session.sv.ds#">
select sysdate thedate from dual
</cfquery>
<cflog file="threadTest6" text="thread running... #i# ... #q1.thedate#">
</cfloop>
<cfcatch type="any">
<cflog file="threadTest6" text="error: #cfcatch.detail# /// #cfcatch.message#">
</cfcatch>
</cftry>
</cfthread>
我让该页面运行几秒钟,然后单击“退出”链接。我的退出过程只做这个...
<!---End session--->
<cfset StructDelete(Session, 'dev')>
<cfset StructDelete(Session, 'sv')>
<cfset StructDelete(Session, 'act')>
<cfset StructClear(Session)>
<!---I cannot use `<cfset sessionInvalidate()>` because not all our customers are up to CF10.--->
发生这种情况时,我希望线程中的所谓重复会话继续进行,并且只结束原始用户的会话。但事实并非如此。这是threadTest6.log的输出...
"Severity","ThreadID","Date","Time","Application","Message"
"Information","cfthread-1","02/24/14","16:26:04",,"C:\ColdFusion10\cfusion\logs\threadTest6.log initialized"
"Information","cfthread-1","02/24/14","16:26:04","CMPRO","thread running... 1 ... 2014-02-24 16:26:04.0"
"Information","cfthread-1","02/24/14","16:26:07","CMPRO","thread running... 2 ... 2014-02-24 16:26:07.0"
"Information","cfthread-1","02/24/14","16:26:10","CMPRO","thread running... 3 ... 2014-02-24 16:26:10.0"
"Information","cfthread-1","02/24/14","16:26:13","CMPRO","thread running... 4 ... 2014-02-24 16:26:13.0"
"Information","cfthread-1","02/24/14","16:26:16","CMPRO","thread running... 5 ... 2014-02-24 16:26:16.0"
"Information","cfthread-1","02/24/14","16:26:19","CMPRO","thread running... 6 ... 2014-02-24 16:26:19.0"
"Information","cfthread-1","02/24/14","16:26:22","CMPRO","error: The value of the attribute datasource, which is currently '', is invalid. /// Attribute validation error for tag CFQUERY."
【问题讨论】:
-
您不能将会话范围内的任何内容复制到线程本地范围内吗?
-
否,因为包含在线程中的代码在 1000 多个地方使用了
session.whatever。这就是我所指的我们无法更改的代码。 -
抱歉,解决方法对您不起作用。我记录了会话,尽管会话过期后似乎一切都在那里,但出于某种奇怪的原因,只能通过使用
form.session.sv.ds或session.sv['DS']访问session.sv.ds。我认为这与 CF 编译器对会话范围进行优化有关,但不适用于form中我们肮脏的 hackysession。这很脏是有原因的,它对你的情况来说太脏了。如果可能的话,我会重构现有代码以不直接引用Session。您可以cfparam并默认使用Session -
是的。哦,好吧,我现在将继续使用我的 cfapplication hack。谢谢你的尝试,@Henry。
-
如果你可以破解一个全新的应用程序并复制会话数据,我不明白为什么你不能将实际代码更改为不使用会话。看来您可以创建一个排队系统来存储相关数据并从中生成 PDF。
标签: multithreading session coldfusion