views:

159

answers:

2

I beheld a web framework implementing in-memory session in this way. The session object is added to Cache with timeout. When the time is out, the session is removed from Cache automatically. To protect race condition, each request should acquire lock on given session object to proceed. Each request will "touch" the session in Cache to refresh the timeout.

Everything looks fine, until this scenario is discovered. Say, one operation takes a long time, longer than timeout. Another request comes and wait on session lock which is currently hold by the long-time request. Finally, the long-time request is over, it releases the lock. But, since it already takes longer time than timeout, the session object is already removed from Cache. This is obvious because the only request holding the lock doesn't have a chance to "touch" the session object in cache. The second request gets the lock but cannot retrieve the expired Session object. Oops...

To fix this issue, the second request has to re-create the Session object. But, this is just like digging a buried dead body from tomb and try to bring it back to life. It causes buggy code.

I'm wondering what's the best way to implement timeout in session to handle such scenario. I know that current platform must have good session mechanism. I just want to know the under-the-hood how.

+1  A: 

Hi Morgan Cheng (Hong Kong people?),

Could your problem be solved by touch-ing the session object when your long-time request finishes?

Let's discuss the solution by an example. When the request arrives, you touch the session and extends it for 5 minutes. When the request ends, you also touch the session and extends it for 1 minute, before releasing the lock. If the result of "end request + one minute" is earlier than "start request + 5 minutes", then use the latter as the timeout; otherwise use the former. (Of course, the 5 minutes and 1 minute could be any value you like.)

I wonder what kind of "cache" you are using. From your description, it seems like the cache destroys the session object "automatically". If this is the case, you may touch the session with a very large timeout value, for example, one day, when the request arrives. When the request ends, you re-touch it using a reasonable value, say, 5 minutes. Or, to be smarter, using the value: (5 minutes - request_time > 1 minute) ? (5 minutes - request_time) : 1 minute), where request_time is the time spent on the request.

Hope this helps.

Asuka Kenji

(from Hong Kong)

Siu Ching Pong - Asuka Kenji
The second solution you suggested should do the trick. Set the expires date to a long future in the beginning, and then setting it back to 5 minutes at the end of request handling.
Morgan Cheng
The "cache" works like ASP.NET Cache. When one object is inserted, you specify the timeout. When time is up, Cache will schedule one thread in ThreadPool to release the object.
Morgan Cheng
So please don't forget to accept my answer (put a tick beside my answer). Thank you! :-)
Siu Ching Pong - Asuka Kenji
+1  A: 

First, I wouldn't do anything in Cache is supposed to be related to Session. If Session needs to kill itself if not used for so many minutes, I would track all of that in Session. Second, I'd be inclined to put a wrapper class around access to the Session so that when any value is accessed or touched, the marker (which itself could be stored in Session) to determine whether it should kill itself as well as the code to "kill the Session" can be encapsulated.

Thomas
You are right. Having Cache to store Session object is a big design defect. It limits Session only be stored in memory, causing scalability issue.
Morgan Cheng