[Web-SIG] Session interface
Ian Bicking
ianb at colorstudy.com
Wed Aug 17 07:31:12 CEST 2005
Mike Orr wrote:
> 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.)
That could be a little difficult, since multiple applications may be
sharing a session. But at the same time, applications that don't expect
ConflictError are going to be pissed if you configure your system for
optimistic locking.
Of course, given a session ID and a session store, each application
could have its own manager. Possibly. Hmm... interesting. In that
case each SessionManager needs an id, which is a bit annoying -- it has
to be stable and shared, because the same SessionManager has to be
identifiable over multiple processes. But I hate inventing IDs all over
the place. I feel like I'm pulling string keys out of my ass, and if
I'm going to pull things out of my ass I at least don't want to then put
them into my code. I sense UUIDs coming on :(
That said, this isn't the only place I need strings that are unique to
an application instance.
> 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)
I think metadata is probably good; or lazily-loaded sessions or
something. The metadata is important I think, because updating metadata
shouldn't be effected by locking and whatnot. I think Mike mentioned a
problem with locking and updating the timestamp contained in the session
-- we should avoid that.
> ... where metadata includes the access time and whatever else we
> decide. Of course, iterating the content may be disk/memory intensive.
Sure. We could have a callback to do filtering too, maybe with a
default filter by expiration time. Or event callbacks.
> 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.
Acquiring or creating a session ID is outside of the scope of this
interface, but I think that's much of what would be useful to
sessionless users. Or, rather, people who want application-specific
sessions.
> 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)?
XML-RPC contains the XML, but it doesn't deal with the transport really.
And, just using XML-RPC as an example, what if you want to stuff the
session ID inside the XML-RPC request instead of in a cookie header?
But anyway, the reason I don't want to handle this is because this would
be much easier if building upon a Standard That Does Not Yet Exist, and
I'd rather avoid overlapping with that standard.
>> 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.
I was thinking of pythonweb's "Store":
http://pythonweb.org/projects/webmodules/doc/0.5.3/html_multipage/lib/node153.html
I vaguely suggest in the interface that each application should put all
of its data in a single key (based on the application name). Now I
think that should be based on a unique name (not the application name,
because the application may exist multiple times in the process), and
maybe with an entirely different manager.
> 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.
In the interface I suggest anything pickleable can go in a key. This
requirement has been the source of some controversy in Webware, since
people wanted to put open file objects and such in the session; mostly
people coming from Java where apparently that's the norm. Anyway, it's
still possible with this interface to have a store that never pickles
anything; I can just hope no one writes code they expect anyone else to
use that demands in-memory session storage. Those are lame even when
you are using threads.
I think the example shows one reason the session shouldn't be considered
a public API. I think it's fine to put the username or the user object
in the session -- we can debate the pluses and minuses, but it works --
but I think you should definitely wrap that implementation detail in
something else. E.g., request.user should return
request.session['user'] or something.
> 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.
I guess if applications each have their own SessionManager, they could
have their own Session classes, and if they wanted to the Session
objects could use application-specific storage and even an
application-specific API (not just a dictionary interface). I don't
know what the point of that would be, though, since it's all
application-specific and not generic, so you might as well just use the
session ID and ignore the rest of the API.
--
Ian Bicking / ianb at colorstudy.com / http://blog.ianbicking.org
More information about the Web-SIG
mailing list