At 8:59 AM -0800 14/2/14, Ron Garret wrote:
On Feb 14, 2014, at 2:31 AM, peter p2.edoc@gmail.com wrote:
I find that I have the same requirement and would like not to re-invent wheels so would much appreciate hearing any insights you gained rg.
Turns out to be very easy. HT sessions can be accessed and set via the generic function ht:session-db, which returns an alist. The alist keys are fixnums and the values are opaque HT::SESSION objects. To make a persistent session all you have to do is serialize and restore this alist. All of the slots of an HT::SESSION are atoms, except for HT::SESSION-DATA, which is an alist, but it contains only values that you put there. So serializing an HT::SESSION is not hard.
The challenging part for me turned out to be restoring Hunchentoot's internal session state on restart, because HT assumes that there is an active request whenever a session is created:
? (make-instance 'ht::session)
Error: Unbound variable: *REQUEST*
So you have to restore sessions using ALLOCATE-INSTANCE instead of MAKE-INSTANCE. Other than that it is completely straightforward. (I ended up writing a little general-purpose object serializer using the MOP.)
For local hosting, I used a persistent global session-ID counter as a patch (ensuring session-IDs can't overlap, but that's not acceptable for cloud hosting. All I need really is persistence of the client's cookie validity, as all state data I keep outside HT.
Not sure I understand this. HT natively provides unique (per server) session id's. If you want to make session id's unique across multiple servers that is a different problem than making sessions persistent. But HT already has a hook for that: the generic function NEXT-SESSION-ID. Is there a reason that doesn't work for you?
We're taking different approaches. Here I am obliged not to make anything persistent in the hunchentoot server file system. So the challenge is to make the cookie itself the only thing that is persistent (so stored in the browser).
My vague plan is:
- ignore the session-ID, use just the cookie-value (as in "0AD9630B5FEA2AEC6E3C24F493B1C0C1") - bypass session-too-old-p for now (later transport the session start time externally to the cookie-value) - so the sequence goes thus:
- incoming url from new client (no cookie) HT makes new session and cookie, and sends cookie back to client - subsequence incoming requests carry a cookie, so handled as usual - re-boot HT (session DB data lost) - original client access (carried cookie) HT has to make a substitute session to serve this client
hence ignore the session ID throughout, and search the session DB using the cookie value, as in:
(defun get-stored-session (cookie-value) (cdr (assoc cookie-value (session-db *acceptor*) :test #'string= :key 'session-string)))
Now I'll have to promulgate the consequences of this shift from managing session by ID to cookie-value.
But I'm worried that I've overlooked something. Why wasn't this approach (indexing session by cookie-value instead of session-ID do in the first place). I.e. I fear there must be a good reason what session-IDs were used. Unless there was a need to prevent session persistence.
I am cowering in anticipation of receiving a castigation for missing the most obvious thing. But persistent session without using any local file store is my requirement.
peter