Skip to content

Commit

Permalink
Add ability to set CONN_HEALTH_CHECKS (#185)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamchainz authored Dec 11, 2022
1 parent ccbcc8f commit f19d497
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 22 deletions.
100 changes: 79 additions & 21 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ Oracle, Oracle (GIS), Redshift, CockroachDB, Timescale, Timescale (GIS) and SQLi
Installation
------------

Installation is simple::
Installation is simple:

.. code-block:: console
$ pip install dj-database-url
Expand All @@ -40,48 +42,104 @@ Usage

1. If ``DATABASES`` is already defined:

- Configure your database in ``settings.py`` from ``DATABASE_URL``::
- Configure your database in ``settings.py`` from ``DATABASE_URL``:

.. code-block:: python
import dj_database_url
import dj_database_url
DATABASES['default'] = dj_database_url.config(
conn_max_age=600,
conn_health_checks=True,
)
DATABASES['default'] = dj_database_url.config(conn_max_age=600)
- Provide a default:

- Provide a default::
.. code-block:: python
DATABASES['default'] = dj_database_url.config(default='postgres://...')
DATABASES['default'] = dj_database_url.config(
default='postgres://...',
conn_max_age=600,
conn_health_checks=True,
)
- Parse an arbitrary Database URL::
- Parse an arbitrary Database URL:

DATABASES['default'] = dj_database_url.parse('postgres://...', conn_max_age=600)
.. code-block:: python
DATABASES['default'] = dj_database_url.parse(
'postgres://...',
conn_max_age=600,
conn_health_checks=True,
)
2. If ``DATABASES`` is not defined:

- Configure your database in ``settings.py`` from ``DATABASE_URL``::
- Configure your database in ``settings.py`` from ``DATABASE_URL``:

.. code-block:: python
import dj_database_url
import dj_database_url
DATABASES = {
'default': dj_database_url.config(
conn_max_age=600,
conn_health_checks=True,
),
}
DATABASES = {'default': dj_database_url.config(conn_max_age=600)}
- You can provide a default, used if the ``DATABASE_URL`` setting is not defined:

- Provide a default::
.. code-block:: python
DATABASES = {'default': dj_database_url.config(default='postgres://...')}
DATABASES = {
'default': dj_database_url.config(
default='postgres://...',
conn_max_age=600,
conn_health_checks=True,
)
}
- Parse an arbitrary Database URL::
- Parse an arbitrary Database URL:

DATABASES = {'default': dj_database_url.parse('postgres://...', conn_max_age=600)}
.. code-block:: python
The ``conn_max_age`` attribute is the lifetime of a database connection in seconds
and is available in Django 1.6+. If you do not set a value, it will default to ``0``
which is Django's historical behavior of using a new database connection on each
request. Use ``None`` for unlimited persistent connections.
DATABASES = {
'default': dj_database_url.parse(
'postgres://...',
conn_max_age=600,
conn_health_checks=True,
)
}
``conn_max_age`` sets the |CONN_MAX_AGE setting|__, which tells Django to
persist database connections between requests, up to the given lifetime in
seconds. If you do not provide a value, it will follow Django’s default of
``0``. Setting it is recommended for performance.

.. |CONN_MAX_AGE setting| replace:: ``CONN_MAX_AGE`` setting
__ https://docs.djangoproject.com/en/stable/ref/settings/#conn-max-age

``conn_health_checks`` sets the |CONN_HEALTH_CHECKS setting|__ (new in Django
4.1), which tells Django to check a persisted connection still works at the
start of each request. If you do not provide a value, it will follow Django’s
default of ``False``. Enabling it is recommended if you set a non-zero
``conn_max_age``.

.. |CONN_HEALTH_CHECKS setting| replace:: ``CONN_HEALTH_CHECKS`` setting
__ https://docs.djangoproject.com/en/stable/ref/settings/#conn-health-checks

Strings passed to `dj_database_url` must be valid URLs; in
particular, special characters must be url-encoded. The following url will raise
a `ValueError`::
a `ValueError`:

.. code-block:: plaintext
postgres://user:p#ssword!@localhost/foobar
and should instead be passed as::
and should instead be passed as:

.. code-block:: plaintext
postgres://user:p%23ssword!@localhost/foobar
Expand Down
5 changes: 4 additions & 1 deletion dj_database_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ def config(
return {}


def parse(url, engine=None, conn_max_age=0, ssl_require=False):
def parse(
url, engine=None, conn_max_age=0, conn_health_checks=False, ssl_require=False
):
"""Parses a database URL."""

if url == "sqlite://:memory:":
Expand Down Expand Up @@ -115,6 +117,7 @@ def parse(url, engine=None, conn_max_age=0, ssl_require=False):
"HOST": hostname,
"PORT": port or "",
"CONN_MAX_AGE": conn_max_age,
"CONN_HEALTH_CHECKS": conn_health_checks,
}
)

Expand Down
18 changes: 18 additions & 0 deletions test_dj_database_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,24 @@ def test_timescalegis_parsing_with_special_characters(self):
assert url["PASSWORD"] == "#password"
assert url["PORT"] == 5431

def test_persistent_connection_variables(self):
url = dj_database_url.parse(
"sqlite://myfile.db", conn_max_age=600, conn_health_checks=True
)

assert url["CONN_MAX_AGE"] == 600
assert url["CONN_HEALTH_CHECKS"] is True

def test_sqlite_memory_persistent_connection_variables(self):
# memory sqlite ignores connection.close(), so persistent connection
# variables aren’t required
url = dj_database_url.parse(
"sqlite://:memory:", conn_max_age=600, conn_health_checks=True
)

assert "CONN_MAX_AGE" not in url
assert "CONN_HEALTH_CHECKS" not in url


if __name__ == "__main__":
unittest.main()

0 comments on commit f19d497

Please sign in to comment.