From 3a6398f42d04ea6a677bf7b6d5115175e9011432 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 15 Jan 2013 21:27:37 -0600 Subject: Add new AlwaysCommitMiddleware to the stack The reason for this is documented in the middleware itself. Without this, pgbouncer is of little use to us since it has to throw away every connection we try to route through it because of unclean disconnects. In theory, with the switch to using pgbouncer for all WSGI originating connections and adding this middleware, we should see a notable decrease in connection time to the database. Signed-off-by: Dan McGee --- main/middleware.py | 40 ++++++++++++++++++++++++++++++++++++++++ settings.py | 1 + 2 files changed, 41 insertions(+) create mode 100644 main/middleware.py diff --git a/main/middleware.py b/main/middleware.py new file mode 100644 index 00000000..a698b13c --- /dev/null +++ b/main/middleware.py @@ -0,0 +1,40 @@ +from django.core.exceptions import MiddlewareNotUsed +from django.db import connections + + +class AlwaysCommitMiddleware(object): + """ + Ensure we always commit any possibly open transaction so we leave the + database in a clean state. Without this, pgbouncer et al. always gives + error messages like this for every single request: + + LOG S-0x1accfd0: db/user@unix:5432 new connection to server + LOG C-0x1aaf620: db/user@unix:6432 closing because: client close request (age=0) + LOG S-0x1accfd0: db/user@unix:5432 closing because: unclean server (age=0) + + We only let this middleware apply for PostgreSQL backends; other databases + don't really require connection pooling and thus the reason for this + middleware's use is non-existent. + + The best location of this in your middleware stack is likely the top, as + you want to ensure it happens after any and all database activity has + completed. + """ + def __init__(self): + for conn in connections.all(): + if conn.vendor == 'postgresql': + return + raise MiddlewareNotUsed() + + def process_response(self, request, response): + """Commits any potentially open transactions at the underlying + PostgreSQL database connection level.""" + for conn in connections.all(): + if conn.vendor != 'postgresql': + continue + db_conn = getattr(conn, 'connection', None) + if db_conn is not None: + db_conn.commit() + return response + +# vim: set ts=4 sw=4 et: diff --git a/settings.py b/settings.py index 8ed5cb61..cdc56e3e 100644 --- a/settings.py +++ b/settings.py @@ -66,6 +66,7 @@ TEMPLATE_LOADERS = ( ) MIDDLEWARE_CLASSES = ( + 'main.middleware.AlwaysCommitMiddleware', 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', -- cgit v1.2.3-55-g3dc8