Link to home
Start Free TrialLog in
Avatar of Ike23
Ike23Flag for United States of America

asked on

Session timeout happens inconsistently

I have an intranet application that has been working for about 3 years.  I am using CF 5 on Win 2000.  I have been getting complaints that my users are being kicked out of the system at random times during the day.  I used to have the session timeout value set to 2 hours and have recently increased that to 9 hours to see if it would fix the problem.  I have set the max value in the CF Administrator to 9 hours as well as the code in my cfapplication page.  

I have a few questions that I've been trying to figure out:

-What would cause an application to suddenly timeout before the session variable should timeout or what would cause a session variable to timeout before the value set in the cfapplication page?

-Could it be an issue with locking session variables?  Is there a quick way to check for unlocked session variables or a way to lock all session variables?  I remember something in the CF Administrator that will allow you to check a certain mode and have the locking effected...

I have an include file on all my pages that does a check for the session variable and if it is not found redirects the user back to the login page.  I'm thinking that is where the system is sending people back out of the system but that means that the session variables either expire or are lost somehow.

Anyone had any similar experience with premature timeouts?  Thanks for any help or suggestions!

Tim
Avatar of Tacobell777
Tacobell777

The only thing I can think of that would do this is when the cf server restarts, or some code kills the session.

Have a look in your log files and make sure the cf server is not restarting itself...
Avatar of Ike23

ASKER

Sorry if this is a stupid question but where would I find the log files?  Do the logs automatically create themselves or do I have to turn them on in the CF Admin?  Why would the server restart itself?  Wouldn't that kill everyone's session at the same time?  This just happens to individuals so I doubt it could be a whole server restart.
Assuming default install of CFMX

C:\CFusionMX\Logs

As for the questions


-What would cause an application to suddenly timeout before the session variable should timeout or what would cause a session variable to timeout before the value set in the cfapplication page?

Poor coding such as memory leaks or infinite loops, etc

-Could it be an issue with locking session variables?  

Yes

-Is there a quick way to check for unlocked session variables or a way to lock all session variables?

I don't know of one other than a find/search of your code for "Session"
Oh I didn't see the CF 5 comment - but the log location should be similar....
true, if the cf server restarts it happens to everyone.
I would have a look anyway, you can look at the cf logs or the event viewer, for cf logs go into the admin and find them, for event viewer just go to administrative tools event viewer
Agreed with above, however one additional question:

Do you use any code to actively kill the session that is called automatically by either a scheduled event or a link?  (i.e. in your 'logoff' script).  Are you completely sure that this script cannot be called from any other location or process - I've worked with someone else's code that 'autotriggered' the destruction of the session structure if a timestamp was beyond a designated CreateTimeSpan() value - so even when the server saw the session as still valid the code would 'clean up' after this supposedly timed-out user.

The other thing to check if the CF logs don't show anything is to check in your server's event viewer to see if there were any memory events (overflows) or if the service force a restart due to an exception of some kind...  The only other thing that might also cause this - but might not be apparent to the user right away is if it boots them after a particular function is performed (or group of functions).  Pretty hard to guess on this one without knowing what your application does, how it's structured, and what the Servers hardware disposition might be (flaky memory, other apps mem leaks, disk write errors, etc.).  If nothing has changed in the CF server software, and nothing has changed in your code - it's most likely something has changed about the hardware or other software running on that server.
OK. A few more than 'one additional question' :)
Maybe you have thought of this, but I did not see it mentioned. Do you have multiple cfapplication.cfm files that might have different time out lengths?
Avatar of Ike23

ASKER

Here's my cfapplication page:

<!--- Global Security Setings --->
<cfapplication
      name="intraNetApp"
      clientmanagement="Yes"
      sessionmanagement="Yes"
      setclientcookies="no"
      sessiontimeout=#sessionvariabletimeout#
      applicationtimeout=#CreateTimeSpan(1,0,0,0)#
      setdomaincookies="no"
>
<!--- IF THE LOGOUT BUTTON IS PUSHED THEN CLEAR THE SESSION VARIABLES AND DELETE THE COOKIES --->
<cfif isdefined("logout")>

<cflock scope="SESSION" type="EXCLUSIVE" timeout="10">
      <cfset structclear(session)>
   <CFCOOKIE NAME="CFID" VALUE="#CFID#" EXPIRES="NOW">
   <CFCOOKIE NAME="CFTOKEN" VALUE="#CFTOKEN#" EXPIRES="NOW">
</cflock>

<cfelse>

<!--- THIS WILL CHECK FOR PERSISTENT COOKIES AND DELETE THEM --->
<cfif (isdefined("Cookie.CFID")) AND (isdefined("Client.LastVisit"))>
  <cfset min_date = #DateAdd('H', -12, Now())#>
  <cfif DateCompare(Client.LastVisit, min_date) IS -1>
    <cfcookie name="CFID" value="#CFID#" expires="NOW">
    <cfcookie name="CFTOKEN" value="#CFTOKEN#" expires="NOW">
  </cfif>
</cfif>

<!--- THIS WILL SET A SESSION COOKIE IF ONE DOESN'T EXIST --->
<CFIF NOT IsDefined("CFID")>
   <CFLOCK SCOPE="SESSION" TYPE="READONLY" TIMEOUT="5">
   <CFCOOKIE NAME="CFID" VALUE="#SESSION.CFID#">
   <CFCOOKIE NAME="CFTOKEN" VALUE="#SESSION.CFTOKEN#">
</CFLOCK>
</CFIF>

<!--- THIS WILL CAUSE THE COOKIE TO EXPIRE ONCE THE BROWSER IS CLOSED --->
   <CFCOOKIE NAME="CFID" VALUE="#CLIENT.CFID#">
   <CFCOOKIE NAME="CFTOKEN" VALUE="#CLIENT.CFTOKEN#">

</cfif>

See anything wrong with the code?

I also have a include file that I put at the top of each page to check for the existence of a session variable to prevent direct browsing to pages within the application (code below):

Security include file:

<cfif isdefined("session.userid") and session.userid neq "">

<cflock timeout="10" type="EXCLUSIVE" scope="SESSION">
     <cfset request.userid = session.userid>
       <cfset request.wgid = session.workgroupid>
</cflock>

<cfelse>

<cflocation url="login.cfm" addtoken="no">

</cfif>      


Also, what do you mean by "leaks".  If I restarted my server would that clean up and leaks and make the system more stable again?  Thanks for any feedback.  This problem is one of those that could have multiple causes so any thoughts are welcomed.
"leaks" would be not using CFLOCK when accessing session variables - with CF 5 you should lock READS and writes, with CFMX you can get away with only writes, but best practice is still to lock both
Avatar of Ike23

ASKER

Would that cause a session to end?  If a session variable was not locked would that mean that someone else could somehow switch values with another person?  I did a bunch of work locking my variables and reading on why to use them but I still haven't grasped why to lock variables other than "you are supposed to".  Would not locking a session variable within a custom tag cause any problems?  Thanks for your help...this problem has been confusing me for months.
Not lockig (especially on versions prior to MX) can cause memory leaks.  Memory leaks can cause all sorts of random problems - including serious ones like taking down/crashing your entire server.

Not locking properly means that two threads of code could be attempting to write to the same place at the same  time.  It also means that one thread could be writing to the variable and another reads the data before it is completely written.  This can cause corruption of the server and the program.

Yes not locking within a custom tag could cause a problem.

I don't know if this is causing your problem of the session ending, but it is possible if the session is getting corrupt that it is being abandoned by the server.
Avatar of Ike23

ASKER

Just to be clear...  I guess I should do a search for "session." and then put code like this around each time a session variable is set or read right?  I do set my session.userid to the request scope in my include file so that I can reference that on some pages.  Would that cause any problems?
It is so hard to say....

But with CF 5 not locking even reads such as :

<cfif isdefined("session.userid") and session.userid neq "">

has been known to crash systems....
Avatar of Ike23

ASKER

So I need to lock around my <cfif> statements?  That is something I don't think that I am doing.  What if there is a ton of code between the <cfif isdefined("session.userid")> will that cause any problems?  I'm starting to think that the locking is probably the problem since it is starting to happen now that I have more concurrent users.
If you do a great deal of work in a conditional just check at the beginning of the script and set a local variable to the state... example:

<cflock scope="session" type="readonly" timeout="10">
<cfscript>
if (isDefined('session.variable')) {
      varUserHasSession = 1;
      } else {
      varUserHasSession = 0;
}
</cfscript>
</cflock>

Now you can just proceed by checking whether or not varUserHasSession = 1 for the rest of the page.

Yes you can just use a <cfparam variable="varUserHasSession" default="0">
And then a <cfif> tag to set the value to 1 if session.variable is defined... but if you don't need to use other tags, putting your conditional statements in a <cfscript> tag has been shown to reduce the processing time required.

Either way works fine.
As another solution... if you have the money for the upgrade, why not use this as a good reason to upgrade to CFMX 6.1 -  then you won't have to lock any of your session reads... just some writes (although I haven't ever had any problems with not locking session vars in MX 6.1 - just Application vars.  It's always good practice tho to lock any variables that may have more than one simultaneous access possible no matter what their scope (or what language you are developing in for that matter).
Avatar of Ike23

ASKER

I'm afraid of upgrading to 6.1 since this is an intranet application that everyone in my company uses daily.  I guess I could try and upgrade on a test server and then see if that works first.  That sounds like the best plan though since I wouldn't have to worry about session locking.  Now you brought up a new point that makes me worry...  Why would I need to lock application variables?  What if I am using a few application variables like application.datasource?  Since the value is always the same for every call to that variable what is the harm in not locking it?
Side note - I added the unnecessary (in my example) timeout argument to the lock.  You need this if the lock is exclusive, but it is optional with read-only because your script essentially is working with a snapshot of the variable in this mode.  If another script updates a value in the variable your code inside the block will not be updated, but you will still be able to check any values for their state at the time the lock was instantiated.  If you make an exclusive lock you must declare a timeout value for the script that is as short as possible without the possibility of it timing out prior to your code fully executing.
Avatar of Ike23

ASKER

I remember setting the timeout to something like 20 or 30.  Is that bad?  Would that cause the app server to restart if it was set to restart in 10 seconds?  Thanks again for letting me pick your brain.  No one on the CF Forums has been as helpful in clearing up what I should actually do with locks and why I should do it.  So do I really need to lock application variables?
ASKER CERTIFIED SOLUTION
Avatar of digicidal
digicidal
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
No that is not a problem... actually I just reread the section in the docs and the timeout is not for the lock itself... my bad... its the time a function will wait to ATTAIN the lock... so setting this to 30 or even 90 is not a problem... the affected code will simply wait longer to set the lock... once the lock is instantiated all code will execute no matter how long it takes... See I learned something today about cflock too. :)  And yes, even with MX 6.1 you should lock any shared scope variables for writing at the very least.  Most reads can occur fine because they happen so quickly and do not actually modify the variable itself.  However with application variable you should really lock both reads and writes since multiple sessions may be writing to or reading from the variable.  With sessions, you need to lock in versions prior to MX, but there is much less chance of corruption because only that user can modify their own session - so unless your code executes two calls which overlap you should be fine.

The real answer tho is this: a lock requires almost nothing in processing time and is invisible to the user - a memory leak may cause your application to fail entirely (and in really bad cases the whole server itself) - and is DEFINITELY visible to the user.  If in no other way than it will slowly degrade the performance of the server, but usually because it will cause intermittent errors and strange behavior that the user doesn't expect.
Avatar of Ike23

ASKER

I still don't see why to lock application reads since they are all the same value but I'll take your word for it.  I guess it's time for me to do a site search for session and set up a test server so I can upgrade to 6.1.  Thanks for your help.

Tim
The reason to lock reads is that someone else COULD be doing a write while the read is happening.

The read lock tells someone trying to write to wait until the read completes so taht they don't read partially written data.

Also the readlock will be postponed if the variable is being written....
If it's going to take a long time to retrofit your application to a well-formed state (using the locks) if you look halfway down the page I gave you a link for there is an option to have the server automatically check for and lock any unlocked shared scope variables.  The cost is server precompilation performance, but you can check that feature while re-tooling your code to minimize any effect of unlocked code first.  Just make sure to go back and uncheck it once you have all your locks in place to return the lost server cycles to other functions.

Good luck!
Avatar of Ike23

ASKER

Is that in the CF Administrator?  What option would you suggest?  I think that would be a good idea for now unless it makes the application so slow it is unusable...
Avatar of Ike23

ASKER

I checked the box that says "Sinlge threaded sessions" in the CF Administrator.  It almost seems like the application is working faster now.  From the description I think that this will at least prevent memory leaks for now until I can upgrade.
Yes, that is correct... by making your sessions single threaded it is basically forcing everything to be locked - so in a sense locks aren't needed... however, if you think it's faster now... just wait until you have your locks in and can once again let it handle multiple actions at once - safely for once!  Glad that helped.