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 loc开发者_Go百科k 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.
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)
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.
精彩评论