[Web-SIG] Session interface, v2
mso at oz.net
Sat Aug 20 21:56:31 CEST 2005
Ian Bicking wrote:
>This version separates out SessionManager from SessionStore, and
>suggests that managers be per-application (or maybe per-framework).
There's per-application/per-framework at the class level and instance
level; I'm not sure which you're referring to.
Regarding the former, I was saying we may be able to make a generic
SessionManager class usable as-is by several frameworks. You seemed to
doubt this, but I argued we should at least try.
The latter only matters in multi-application deployments, where several
applications (possibly different frameworks) are sharing a session.
Several features below seem to exist only for this environment, and I'm
having a hard time evaluating them without knowing the complete use
cases you're trying to support. You've said bits about that but maybe
we can flesh it out.
* Scenario 1: Two apps mounted at /foo and /bar, using a common Paste
dispatcher. Both applications are embedded in the same process.
(threaded or asynchronous servers)
* Scenario 2: Same, but the apps are in separate processes. The
dispatcher remains. (forking servers)
* Scenario 3: Two apps mounted at /foo and /bar, using separate handlers
in the Apache config. At no point is there a common Python process
* Scenario 4: Two apps in different virtual hosts.
* Scenario 5: Two apps in different webservers.
* Others: ??
Which situations are you trying to support, which session-related
objects would there be, and how would they interrelate? At what point
do we say scenarios won't attract enough users to justify our time?
I'm also not sure how these would relate to your "application inversion"
paradigm. I'm used to applications as single long-running units that
can hold shared state. But your Paste implementation seems to suggest
instantiating the application for each URL, and maybe the application
would last for only one request. I'm not sure how easy that will be to
port some applications to it, or how this impacts the session
> Raised when an invalid session ID is used.
>class SessionNotFound(SessionError, LookupError):
> Raised when a session can't be found.
> Raised when the ``locking_policy`` is ``optimistic``, and a
> session being saved is stale.
Could go into a SessionCookie class, along with anything else that can
be used by both session-based and sessionless fans.
Is this just an extra, or what are listeners for? Is this for
per-application behavior with a shared manager?
> id = """The string-identifier for this session manager.
> All applications that share this session manager need to use the
> same id when creating the session manager.
With this rule I was expecting some central repository of session
managers, and factory functions a la logger.getLogger(), but there
doesn't seem to be any. What's the purpose of the SessionManager id?
> locking_policy = """The lock policy.
> This is one of these strings:
> Optimistic locking; concurrent sessions may be opened for writing;
> however, if a session is saved that was loaded before the last save
> of the session, a ConflictError will be raised.
> First-come-first-serve. No locking is done; if a session is written
> it overwrites any other session data that was written.
> All sessions opened for writing are serialized; the request is
> blocked until session is available to be opened.
Optimistic locking sounds like a pain. The application would have to
catch the error and then... what? Say "Sorry, your form input was
thrown away." Redo the operation somehow (isn't that the same as lossy
operation?). Reconcile the two states somehow (how?)? Not that we
shouldn't provide it, just that it will need more howto documentation.
> def delete_expired_sessions():
> """Scan for and delete any expired sessions.
> ???: How are sessions defined to be expired? Should listeners
> participate? Should they be able to cancel an expiration?
> def session_ids():
> """Return a list of session IDs.
> ???: Should this return other metadata, like last accessed
If so, it shouldn't be called .session_ids().
> manager = """Reference to parent ISessionManager object"""
> def __init__(id, manager, read_only, last_accessed, creation_time,
> """Create the session object
> def touch():
> """Update the session's last_accessed time.
> Typically just calls ``self.manager.touch(self.id)``
> def commit():
> """Calls ``self.manager.save_session(self)``
> def rollback():
> """Calls ``self.manager.unlock_session(self)``.
> Also calls ``session_listener.rollback(self)``.
These look like they don't belong here. The application already has a
reference to the SessionManager and should call it directly. It points
up a difference in philosophy between the session being a "dumb object"
(no reference to the manager) vs being manager-aware. Is the latter
necessary? Are you thinking of cases where the session would be
provided by the middleware, then the application would have dispose of
the session at the end of the request? The middleware could provide a
reference to the session manager for this. Although that would expose
> class ISessionStore:
> def load_session(session_store_id, session_id, read_only,
> def session_ids(session_store_id):
> def delete_session(session_store_id, session_id):
> def touch(session_store_id, session_id):
> def write_lock_session(session_store_id, session_id):
Isn't session_store_id 'self'? Specifying it seems to imply this is a meta SessionStore, not an individual store. Why would a deployment have multiple stores?
More information about the Web-SIG