On Wed, Dec 22, 2010 at 2:48 AM, edwincheese <[email protected]> wrote: > Hi > > Sorry for bringing back this rather old thread. I am going to add some > more information on the discussion of this issue. > > We have constantly encountered the exactly same issue mentioned by > Josh with Pylons and repoze.who 1.0 in a low traffic web application. > After analysed the check out pattern of SQLAlchemy connection pool, we > concluded that repoze.*, friendlyformplugin, and SQLAlchemyPlugin > cause this problem. (For other people having the "MySQL server gone > away" issue, I suggest you check pool_recycle directive of SQLAlachemy > first if you have not) > > As Josh mentioned, SQLAlahcmey expect the session to be closed after > use. For web application, SQLAlachemy recommend closing the session at > the end of every request. Pylons followed this recommendation by > removing the session in the "finally" clause in the BaseController. So > when a request pass through the BaseController, the SQLAlachemy > session would always be properly cleaned up. > > However it is not the case that every request would pass through the > BaseController when using repoze.*, friendlyformplugin and > SQLAlchemyPlugin. > > Here is a simplified view of how a **normal** request use a SQLAlchemy > session (I assumed using default configuration of Pylons so sessions > are in fact SQLAlchemy's scoped_session; and the user is logged in): > > == Normal Request == > 1. Request come in > 2. SQLAlchemyPlugin use Session to retrieve user object. > scoped_session create the underlying session object and hence a > connection is checked out from connection pool. > 3. repoze.who's PluggableAuthenticationMiddleware pass control to > downstream middleware. > 4. Control pass to controller action, controller use Session to query > the database. > 5. Session.remove() called in BaseController to clean up the session > and return connection to connection pool > 6. Completing request and return result to user. > 7. Thread wait for another request. > > The problem occurred when requesting friendlyform's login_handler and > logout_handler url. Here is how the login/logout request use a > SQLAlchemy session: > > == Problematic Request (Login) == > 1. Request come in > 2. Friendlyform handle the request > 3. Invoke SQLAlchemyPlugin to check login credential, it use Session > to query the user model. Hence, scoped_session create the underlying > session object and hence a connection is checked out from connection > pool. > 4. Credential accepted, Friendlyform set > environ['repoze.who.application'] to a HTTPFound instance (for > redirecting user to the post_login_path) > 5. repoze.who's PluggableAuthenticationMiddleware execute HTTPFound > instead of statically configured downstream middleware, thus Pylons > controllers are not executed > 6. 302 Found send to user to redirect to post_login_path. Request > completed. > 7. Thread wait for another request.
It sounds like a bug in FriendlyForm. If it's using the scoped session, it should remove it in just before returning. I don't think it matters if Session.remove() is called twice, once by the application and once by the middleare. The only problem would be if a farther-out middleware wants to do some postprocessing on some objects it fetched during preprocessing. But that's rare, and having Session.remove() in the application would have prevented it from working anyway. The other alternative is to use a separate scoped session and separate engine for the middleware, so that it's not sharing connections with the application. This all does show the limitations of combining global state (a shared scoped session) with middleware (which doesn't know whether other middleware has removed the session). -- Mike Orr <[email protected]> -- You received this message because you are subscribed to the Google Groups "pylons-discuss" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/pylons-discuss?hl=en.
