The short version is "yes", as it turns out. I did not expect that.
This question came up today courtesy of Ron Stewart on Twitter:
Anyone know if @ColdFusion clears a session which expires during a long-running request? E.g., session vars exist at front but disappear?
— Ron Stewart (@oneofwe3geeks) June 17, 2014
Ron didn't specifically ask me, but it's one of those things I figured I should know, but found I didn't know for sure, so I had better test it out.
As it turns out, both ColdFusion and Railo will happily time-out sessions and applications whilst requests within those sessions / applications are still running. I dunno what I think about this, but my initial reaction is "that's not great".
Here's my test code:
// Application.cfc
component {
variables.requestStartTime = getTickCount();
this.name = "timeoutTest13";
this.sessionManagement = true;
this.applicationTimeout = createTimespan(0,0,2,0);
this.sessionTimeout = createTimespan(0,0,1,0);
function onApplicationStart(){
writeLog(file=this.name, text="#getFunctionCalledName()# @ #getTickCount()-variables.requestStartTime#");
}
function onSessionStart(){
writeLog(file=this.name, text="#getFunctionCalledName()# @ #getTickCount()-variables.requestStartTime#");
}
function onRequestStart(){
writeLog(file=this.name, text="#getFunctionCalledName()# @ #getTickCount()-variables.requestStartTime#");
}
function onRequest(){
include arguments[1];
}
function onRequestEnd(){
writeLog(file=this.name, text="#getFunctionCalledName()# @ #getTickCount()-variables.requestStartTime#");
}
function onSessionEnd(){
writeLog(file=this.name, text="#getFunctionCalledName()# @ #getTickCount()-variables.requestStartTime#");
}
function onApplicationEnd(){
writeLog(file=this.name, text="#getFunctionCalledName()# @ #getTickCount()-variables.requestStartTime#");
}
}
This is simple: it simply logs when various event handlers are fired.
And a baseline test:
<cfscript>
// baseline.cfm
writeLog(file=this.name, text="top of #listLast(getCurrentTemplatePath(), '/\')# @ #getTickCount()-variables.requestStartTime#");
</cfscript>
This is just to demonstrate the thing works. Typical output would be (this is from ColdFusion 11):
"Severity","ThreadID","Date","Time","Application","Message"
"Information","ajp-bio-8014-exec-1","06/17/14","18:47:12",,"C:\apps\adobe\ColdFusion\11\full\cfusion\logs\timeoutTest02.log initialized"
"Information","ajp-bio-8014-exec-1","06/17/14","18:47:12","TIMEOUTTEST02","onApplicationStart @ 32"
"Information","ajp-bio-8014-exec-1","06/17/14","18:47:12","TIMEOUTTEST02","onSessionStart @ 36"
"Information","ajp-bio-8014-exec-1","06/17/14","18:47:12","TIMEOUTTEST02","onRequestStart @ 37"
"Information","ajp-bio-8014-exec-1","06/17/14","18:47:12","TIMEOUTTEST02","top of baseline.cfm @ 46"
"Information","ajp-bio-8014-exec-1","06/17/14","18:47:12","TIMEOUTTEST02","onRequestEnd @ 47"
"Information","scheduler-1","06/17/14","18:48:19","TIMEOUTTEST02","onSessionEnd @ 67418"
"Information","scheduler-1","06/17/14","18:49:37",,"onApplicationEnd @ 145593"
So the application starts, the session starts, the request starts, runs, ends, and then after their timeouts, the session and applications end too. All as expected.
Next I had two tests: one with a request which ran longer than the 1min session timeout, and another which ran longer than the 2min application timeout:
<cfscript>
// requestLongerThanSessionTimeout.cfm
writeLog(file=this.name, text="top of #listLast(getCurrentTemplatePath(), '/\')# @ #getTickCount()-variables.requestStartTime#");
sleep(90*1000);
writeLog(file=this.name, text="bottom of #listLast(getCurrentTemplatePath(), '/\')# @ #getTickCount()-variables.requestStartTime#");
</cfscript>
<cfscript>
// requestLongerThanApplicationTimeout.cfm
writeLog(file=this.name, text="top of #listLast(getCurrentTemplatePath(), '/\')# @ #getTickCount()-variables.requestStartTime#");
sleep(150*1000);
writeLog(file=this.name, text="bottom of #listLast(getCurrentTemplatePath(), '/\')# @ #getTickCount()-variables.requestStartTime#");
</cfscript>
And we see from their logs (I'll just show the latter one, as they're both thematically the same):
"Severity","ThreadID","Date","Time","Application","Message"
"INFO","qtp1678014056-13","06/17/2014","18:59:07","","onApplicationStart @ 1"
"INFO","qtp1678014056-13","06/17/2014","18:59:07","","onSessionStart @ 5"
"INFO","qtp1678014056-13","06/17/2014","18:59:07","","onRequestStart @ 6"
"INFO","qtp1678014056-13","06/17/2014","18:59:07","","top of requestLongerThanApplicationTimeout.cfm @ 21"
"INFO","Thread-16","06/17/2014","19:00:29","","onSessionEnd @ 82145"
"INFO","Thread-16","06/17/2014","19:01:29","","onApplicationEnd @ 142174"
"INFO","qtp1678014056-13","06/17/2014","19:01:37","","bottom of requestLongerThanApplicationTimeout.cfm @ 150022"
"INFO","qtp1678014056-13","06/17/2014","19:01:37","","onRequestEnd @ 150026"
(this is from Railo this time)
Here we see:
- the request starts
- the session times out
- the application times out
- the request finishes
Now I kinda think that both session and application should be kept alive whilst things are still happening, because the way it currently works will leave the application (/session) in possibly an "unknown" state during the course of a request, and also there's no real way of saying "oi, don't timeout!" if we know a request might push the envelope there a bit.
Worth raising a bug / enhancement request? What behaviour did you expect here?
--
Adam