[Web-SIG] Session interface

Mike Orr mso at oz.net
Wed Aug 17 06:54:48 CEST 2005


Regarding Ian's session interface:
http://svn.colorstudy.com/home/ianb/scarecrow_session_interface.py

Ian Bicking wrote:

>Thinking on it more, probably a good place to start would be agreeing on 
>specific terminology for the objects involved, since I've seen several 
>different sets of terminology, many of which use the same words for 
>different ideas:
>
>Session:
>   An instance of this represents one user/browser's session.
>SessionStore:
>   An instance of this represents the persistence mechanism.  This
>   is a functional component, not embodying any policy.
>SessionManager:
>   This is a container for sessions, and uses a SessionStore.  This
>   contains all the policy for loading, saving, locking, expiring
>   sessions.
>  
>


At minimum, the SessionManager links the SessionStore, Session, and 
application together.  It can be generic, along with 
loading/saving/locking.  (Although we might allow the application to 
choose a locking policy.)  But expiring is very application-specific, 
and it may not be the "application" doing it but a separate cron job.  
Perhaps most applications will be happy with an "expire all sessions 
unmodified for N minutes", but some will want to inspect the metadata 
and others the content.  So maybe all the SessionManager can do is:

    .delete_session(id)   => pass message directly to SessionStore
    .iter_sessions()  =>  tuples of (id, metadata)
    .iter_sessions_with_content() => tuples of (id, metadata, content)

... where metadata includes the access time and whatever else we 
decide.  Of course, iterating the content may be disk/memory intensive.

If .delete_expired_sessions() is included, the application would have to 
subclass SessionManager rather than just using it.  That's not 
necessarily bad but a potential limitation.  Or the application could 
kludge up a policy from your methods:

    cutoff = time.time() - (60 * 60 * 4)
    for sid in sm.session_ids():
        if sm.last_accessed(sid) < cutoff:
            sm.delete_session(sid)

I suppose kludgy is in the eye of the beholder.  This would not be kludgy:

    cutoff = time.time() - (60 * 60 * 4)
    for sid, metadata in sm.iter_sessions():
        if metadata.atime < cutoff:
            sm.delete_session(sid)

Curses on anybody who says, "What's the difference?"

PS. Kudos for using .names_with_underscores rather than .studlyCaps.

Your other methods look all right at first glance.  We'll know when we 
port existing frameworks to it whether it's adequate.  (Or should that 
be "when we port it to existing frameworks"?  Or "when we make existing 
frameworks use it as middleware"?)  We'll also have to keep an eye on a 
usage pattern to recommend for future frameworks, and on whether this 
API has anything to do with the "sessionless" persistance patterns that 
have also been proposed. 

Interesting ideas you've had about read/write vs read-only sessions.  
I'd say let's support read-only sessions, and maybe that will encourage 
applications to use them.

Session ID cookies seem like a generic thing this class should handle, 
especially for applications that don't otherwise use cookies.  XML-RPC 
encapsulates the XML (an necessary evil); why shouldn't we encapsulate 
the cookie (another necessary evil)?

>Does that sound good?  Note that the attached interface conflates 
>SessionStore and SessionManager.  Some interfaces make an explicit 
>ApplicationSession, which is contained by Session and keyed off some 
>application ID; my interface implies that separation, but does not 
>enforce it, and does not offer any extra functionality at that level 
>(e.g., per-ApplicationSession locks or transactions).
>  
>


I'm not sure what you mean by ApplicationSession.  Perl's session object 
is a dictionary, and you can store anything in it.  Our top-level object 
has to be flexible due to grandfathering, unless we want to force 
applications to translate to/from our session object to their native 
session format.  Yet you define certain attributes/methods the Session 
must have, which legacy Sessions don't.  I guess allow the application 
to provide a subclass or compatible class, and let it worry about how to 
upgrade its native session object.

Regarding sessionless persistence, that reminds me of a disagreement I 
had with Titus in designing session2.  Quixote provides Session.user 
default None, but doesn't define what other values it can have.  I put a 
full-fledged User object with username/group/permission info.  Titus 
puts a string name and stores everything else in his application 
database.  So his *SessionStore classes put the name in a VARCHAR column 
and didn't save the rest of the session data.  I argued that "most 
people will have a User object, and they'll expect the entire Session to 
be pickled because that's what PHP/Perl do."  He relented, so the 
current *SessionStores can be used either way.

Perhaps applications should store all session data directly, keyed by 
session ID (and perhaps "username"), rather than using pickled 
Sessions.  That would be a good idea for a parallel project.  I'm not 
sure how relevant that would be to this API except to share "cookie 
code".  This API + implementations are required in any case, both 
because "most users" will not consider Python if it doesn't have "robust 
session handling", and a common library would allow frameworks to use it 
rather than reinventing the wheel incompatibly.  This is true regardless 
of the merits of sessions.

-- Mike Orr <mso at oz.net>


More information about the Web-SIG mailing list