Barry Warsaw pushed to branch master at mailman / Mailman
Commits: 856d239e by Mark Sapiro at 2017-03-27T11:36:55-07:00 Implement SQLAlchemy pre-ping to detect dropped connections. - - - - - 21385905 by Barry Warsaw at 2017-03-27T21:06:46+00:00 Merge branch 'sa-ping' into 'master' Implement SQLAlchemy pre-ping to detect dropped connections. Closes #313 See merge request !254 - - - - - 2 changed files: - src/mailman/database/base.py - src/mailman/docs/NEWS.rst Changes: ===================================== src/mailman/database/base.py ===================================== --- a/src/mailman/database/base.py +++ b/src/mailman/database/base.py @@ -23,7 +23,7 @@ from mailman.config import config from mailman.interfaces.database import IDatabase from mailman.utilities.string import expand from public import public -from sqlalchemy import create_engine +from sqlalchemy import create_engine, event, exc, select from sqlalchemy.orm import sessionmaker from zope.interface import implementer @@ -107,3 +107,43 @@ class SABaseDatabase: session = sessionmaker(bind=self.engine) self.store = session() self.store.commit() + # This is from the Dealing with Disconnects section at + # <http://docs.sqlalchemy.org/en/latest/core/pooling.html>. It + # establishes connection pinging to deal with lost connections due to + # database server restarts or other outside events. + # + # XXX This can all be removed once SQLAlchemy 1.2 is released, and we + # pass `pool_pre_ping=True` to create_engine(). + @event.listens_for(self.engine, 'engine_connect') # noqa: E306 + def ping_connection(connection, branch): # pragma: no cover + if branch: + # "branch" refers to a sub-connection of a connection; + # we don't want to bother pinging on these. + return + # Turn off "close with result". This flag is only used with + # "connectionless" execution, otherwise will be False in any case. + old_scwr = connection.should_close_with_result + connection.should_close_with_result = False + try: + # Run a SELECT 1. Use a core select() so that the SELECT of a + # scalar value without a table is appropriately formatted for + # the backend. + connection.scalar(select([1])) + except exc.DBAPIError as error: + # Catch SQLAlchemy's DBAPIError, which is a wrapper for the + # DBAPI's exception. It includes a .connection_invalidated + # attribute which specifies if this connection is a + # "disconnect" condition, which is based on inspection of the + # original exception by the dialect in use. + if error.connection_invalidated: + # Run the same SELECT again - the connection will + # re-validate itself and establish a new connection. The + # disconnect detection here also causes the whole + # connection pool to be invalidated so that all stale + # connections are discarded. + connection.scalar(select([1])) + else: + raise + finally: + # Restore "close with result". + connection.should_close_with_result = old_scwr ===================================== src/mailman/docs/NEWS.rst ===================================== --- a/src/mailman/docs/NEWS.rst +++ b/src/mailman/docs/NEWS.rst @@ -140,6 +140,9 @@ Command line Database -------- * MySQL is now an officially supported database. Given by Abhilash Raj. + * Fix a problem with tracebacks when a PostgreSQL database is power cycled + while Mailman is still running. This ports an upstream SQLAlchemy fix to + Mailman in lieu of a future SQLAlchemy 1.2 release. (Closes: #313) Interfaces ---------- View it on GitLab: https://gitlab.com/mailman/mailman/compare/775216d81ba75e00bfcbb482e075f473d12e99c4...213859054668ad64c0ea66f188beb1c239e4a0c0
_______________________________________________ Mailman-checkins mailing list Mailman-checkins@python.org Unsubscribe: https://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org