From 8217b91aa47063aca0ae0e55cf85cace0ea1ba3f Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Wed, 14 Nov 2012 05:06:31 -0800 Subject: [PATCH] add sqlerror_tween --- edbob/pyramid/tweens.py | 59 +++++++++++++++++++ .../edbob/+package+/pyramid/__init__.py_tmpl | 26 ++++---- 2 files changed, 70 insertions(+), 15 deletions(-) create mode 100644 edbob/pyramid/tweens.py diff --git a/edbob/pyramid/tweens.py b/edbob/pyramid/tweens.py new file mode 100644 index 0000000..8039efa --- /dev/null +++ b/edbob/pyramid/tweens.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +################################################################################ +# +# edbob -- Pythonic Software Framework +# Copyright © 2010-2012 Lance Edgar +# +# This file is part of edbob. +# +# edbob is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# edbob is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for +# more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with edbob. If not, see . +# +################################################################################ + +""" +``edbob.pyramid.tweens`` -- Tween Factories +""" + +import sqlalchemy.exc + +from transaction.interfaces import TransientError + + +def sqlerror_tween_factory(handler, registry): + """ + Produces a tween which will convert ``sqlalchemy.exc.OperationalError`` + instances (caused by database server restart) into a retryable + ``transaction.interfaces.TransientError`` instance, so that a second + attempt may be made to connect to the database before really giving up. + + .. note:: + This tween alone is not enough to cause the transaction to be retried; + it only marks the error as being *retryable*. If you wish more than one + attempt to be made, you must define the ``tm.attempts`` setting within + your Pyramid app configuration. See `Retrying + `_ + for more information. + """ + + def sqlerror_tween(request): + try: + response = handler(request) + except sqlalchemy.exc.OperationalError, error: + if error.connection_invalidated: + raise TransientError(str(error)) + raise + return response + + return sqlerror_tween diff --git a/edbob/scaffolds/edbob/+package+/pyramid/__init__.py_tmpl b/edbob/scaffolds/edbob/+package+/pyramid/__init__.py_tmpl index efdc27d..155371b 100644 --- a/edbob/scaffolds/edbob/+package+/pyramid/__init__.py_tmpl +++ b/edbob/scaffolds/edbob/+package+/pyramid/__init__.py_tmpl @@ -7,10 +7,8 @@ import os.path from pyramid.config import Configurator -from pyramid.authentication import SessionAuthenticationPolicy import edbob -from edbob.pyramid.auth import EdbobAuthorizationPolicy def main(global_config, **settings): @@ -27,24 +25,18 @@ def main(global_config, **settings): # * Raise an exception if a setting is missing or invalid. # * Convert values from strings to their intended type. - settings['mako.directories'] = [ - '{{package}}.pyramid:templates', - 'edbob.pyramid:templates', - ] + settings.setdefault('mako.directories', [ + '{{package}}.pyramid:templates', + 'edbob.pyramid:templates', + ]) + + # Make two attempts when "retryable" errors happen during transactions. + settings.setdefault('tm.attempts', 2) config = Configurator(settings=settings) # Configure edbob edbob.init('{{package}}', os.path.abspath(settings['edbob.config'])) - - # Configure session - config.include('pyramid_beaker') - - # Configure auth - config.set_authentication_policy(SessionAuthenticationPolicy()) - config.set_authorization_policy(EdbobAuthorizationPolicy()) - - # Include "core" stuff provided by edbob. config.include('edbob.pyramid') # Additional config is defined elsewhere within {{project}}. This includes @@ -53,4 +45,8 @@ def main(global_config, **settings): config.include('{{package}}.pyramid.subscribers') config.include('{{package}}.pyramid.views') + # Consider PostgreSQL server restart errors to be "retryable." + config.add_tween('edbob.pyramid.tweens.sqlerror_tween_factory', + under='pyramid_tm.tm_tween_factory') + return config.make_wsgi_app()