db: move Session.remove to outer wsgi layer and also add it

to hooks daemon to avoid leaving connections open in the db pool
fixes #4173, refs #4166
This commit is contained in:
Daniel Dourvaris 2016-08-13 02:56:48 +03:00
parent d269357805
commit e6833d2fd8
4 changed files with 59 additions and 34 deletions

View file

@ -39,6 +39,7 @@ from routes.middleware import RoutesMiddleware
import routes.util
import rhodecode
from rhodecode.model import meta
from rhodecode.config import patches
from rhodecode.config.routing import STATIC_FILE_PREFIX
from rhodecode.config.environment import (
@ -158,6 +159,10 @@ def make_pyramid_app(global_config, **settings):
pyramid_app = config.make_wsgi_app()
pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
pyramid_app.config = config
# creating the app uses a connection - return it after we are done
meta.Session.remove()
return pyramid_app
@ -374,7 +379,25 @@ def wrap_app_in_wsgi_middlewares(pyramid_app, config):
pyramid_app = make_gzip_middleware(
pyramid_app, settings, compress_level=1)
return pyramid_app
# this should be the outer most middleware in the wsgi stack since
# middleware like Routes make database calls
def pyramid_app_with_cleanup(environ, start_response):
try:
return pyramid_app(environ, start_response)
finally:
# Dispose current database session and rollback uncommitted
# transactions.
meta.Session.remove()
# In a single threaded mode server, on non sqlite db we should have
# '0 Current Checked out connections' at the end of a request,
# if not, then something, somewhere is leaving a connection open
pool = meta.Base.metadata.bind.engine.pool
log.debug('sa pool status: %s', pool.status())
return pyramid_app_with_cleanup
def sanitize_settings_and_apply_defaults(settings):

View file

@ -30,6 +30,7 @@ import Pyro4
import pylons
import rhodecode
from rhodecode.model import meta
from rhodecode.lib import hooks_base
from rhodecode.lib.utils2 import (
AttributeDict, safe_str, get_routes_generator_for_server_url)
@ -64,7 +65,10 @@ class HooksHttpHandler(BaseHTTPRequestHandler):
def _call_hook(self, method, extras):
hooks = Hooks()
result = getattr(hooks, method)(extras)
try:
result = getattr(hooks, method)(extras)
finally:
meta.Session.remove()
return result
def log_message(self, format, *args):

View file

@ -406,8 +406,11 @@ class SimpleVCS(object):
yield chunk
finally:
# invalidate cache on push
if action == 'push':
self._invalidate_cache(repo_name)
try:
if action == 'push':
self._invalidate_cache(repo_name)
finally:
meta.Session.remove()
def _get_repository_name(self, environ):
"""Get repository name out of the environmnent

View file

@ -40,40 +40,35 @@ def pylons_compatibility_tween_factory(handler, registry):
from pyramid. For example while rendering an old template that uses the
'c' or 'h' objects. This tween sets up the needed pylons globals.
"""
try:
config = rhodecode.CONFIG
environ = request.environ
session = request.session
session_key = (config['pylons.environ_config']
.get('session', 'beaker.session'))
config = rhodecode.CONFIG
environ = request.environ
session = request.session
session_key = (config['pylons.environ_config']
.get('session', 'beaker.session'))
# Setup pylons globals.
pylons.config._push_object(config)
pylons.request._push_object(request)
pylons.session._push_object(session)
environ[session_key] = session
pylons.url._push_object(URLGenerator(config['routes.map'],
environ))
# Setup pylons globals.
pylons.config._push_object(config)
pylons.request._push_object(request)
pylons.session._push_object(session)
environ[session_key] = session
pylons.url._push_object(URLGenerator(config['routes.map'],
environ))
# TODO: Maybe we should use the language from pyramid.
translator = _get_translator(config.get('lang'))
pylons.translator._push_object(translator)
# TODO: Maybe we should use the language from pyramid.
translator = _get_translator(config.get('lang'))
pylons.translator._push_object(translator)
# Get the rhodecode auth user object and make it available.
auth_user = get_auth_user(environ)
request.user = auth_user
environ['rc_auth_user'] = auth_user
# Get the rhodecode auth user object and make it available.
auth_user = get_auth_user(environ)
request.user = auth_user
environ['rc_auth_user'] = auth_user
# Setup the pylons context object ('c')
context = ContextObj()
context.rhodecode_user = auth_user
attach_context_attributes(context, request)
pylons.tmpl_context._push_object(context)
return handler(request)
finally:
# Dispose current database session and rollback uncommitted
# transactions.
meta.Session.remove()
# Setup the pylons context object ('c')
context = ContextObj()
context.rhodecode_user = auth_user
attach_context_attributes(context, request)
pylons.tmpl_context._push_object(context)
return handler(request)
return pylons_compatibility_tween