Skip to content

Commit

Permalink
fixes #181 - add env var to enable SQLAlchemy pool_pre_ping
Browse files Browse the repository at this point in the history
  • Loading branch information
jantman committed Feb 25, 2018
1 parent 7e50382 commit 3d7aefb
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Unreleased Changes
* Add a new ``migrations`` tox environment that automatically tests all database migrations (forward and reverse) and also validates that the database schema created from the migrations matches the one created from the models.
* Add support for writing tests of data manipulation during database migrations, and write tests for the migration in for Issue 105, above.
* Add support for ``BIWEEKLYBUDGET_LOG_FILE`` environment variable to cause Flask application logs to go to a file *in addition to* STDOUT.
* Add support for ``SQL_POOL_PRE_PING`` environment variable to enable SQLAlchemy ``pool_pre_ping`` feature (see `Disconnect Handling - Pessimistic <http://docs.sqlalchemy.org/en/latest/core/pooling.html#pool-disconnects-pessimistic>`_) for resource-constrained systems.

0.7.1 (2018-01-10)
------------------
Expand Down
7 changes: 6 additions & 1 deletion biweeklybudget/alembic/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"""

from __future__ import with_statement
import os
from alembic import context
from sqlalchemy import pool, create_engine
from logging.config import fileConfig
Expand Down Expand Up @@ -92,7 +93,10 @@ def run_migrations_online():
and associate a connection with the context.
"""
connectable = create_engine(DB_CONNSTRING, poolclass=pool.NullPool)
connectable = create_engine(
DB_CONNSTRING, poolclass=pool.NullPool,
pool_pre_ping=('SQL_POOL_PRE_PING' in os.environ)
)

with connectable.connect() as connection:
context.configure(
Expand All @@ -103,6 +107,7 @@ def run_migrations_online():
with context.begin_transaction():
context.run_migrations()


if context.is_offline_mode():
run_migrations_offline()
else:
Expand Down
3 changes: 3 additions & 0 deletions biweeklybudget/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@
if settings.DB_CONNSTRING.startswith('mysql'):
engine_args['connect_args'] = {'sql_mode': 'TRADITIONAL'}

if 'SQL_POOL_PRE_PING' in os.environ:
engine_args['pool_pre_ping'] = True

#: The database engine object; return value of
#: :py:func:`sqlalchemy.create_engine`.
engine = create_engine(settings.DB_CONNSTRING, **engine_args)
Expand Down
5 changes: 5 additions & 0 deletions docs/source/flask_app.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,8 @@ Logging
-------

By default, the Flask application's logs go to STDOUT. The ``BIWEEKLYBUDGET_LOG_FILE`` environment variable can be set to the absolute path of a file, to cause Flask application logs to go to the file *in addition to* STDOUT.

MySQL Connection Errors
-----------------------

See :ref:`Getting Started - MySQL Connection Errors <getting_started.mysql_connection_errors>` for some information on handling MySQL connection errors.
12 changes: 12 additions & 0 deletions docs/source/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ require specific formatting of their values; see the
:py:mod:`settings module documentation <biweeklybudget.settings>` for a list
of these variables and the required formats.

There are also some additional environment variables available:

* ``BIWEEKLYBUDGET_LOG_FILE`` - By default, the Flask application's logs go to STDOUT. The ``BIWEEKLYBUDGET_LOG_FILE`` environment variable can be set to the absolute path of a file, to cause Flask application logs to go to the file *in addition to* STDOUT.


Running Locally
---------------

Expand Down Expand Up @@ -219,6 +224,13 @@ So using that, we could run biweeklybudget listening on port 8080 and using our
You may need to adjust those commands depending on your operating system, Docker networking mode, and MySQL server.

.. _getting_started.mysql_connection_errors:

MySQL Connection Errors
+++++++++++++++++++++++

On resource-constrained systems or with MySQL servers tuned for minimal resource utilization, you may see the Flask application returning HTTP 500 errors after periods of inactivity, with the Flask application log reporting something like "Lost connection to MySQL server during query" and MySQL reporting "Aborted connection" errors. This is due to connections in the SQLAlchemy connection pool timing out, but the application not being aware of that. If this happens, you can set the ``SQL_POOL_PRE_PING`` environment variable (to any value). This will enable SQLAlchemy's ``pool_pre_ping`` feature (see `Disconnect Handling - Pessimistic <http://docs.sqlalchemy.org/en/latest/core/pooling.html#pool-disconnects-pessimistic>`_) which tests that connections are still working before executing queries with them.

Settings Module Example
+++++++++++++++++++++++

Expand Down

0 comments on commit 3d7aefb

Please sign in to comment.