#34914: Postgres connection is not restarted after it's dropped by the server, even if we use CONN_HEALTH_CHECKS=True -------------------------------------+------------------------------------- Reporter: Vitor | Owner: nobody Menegat | Type: Bug | Status: new Component: Database | Version: 4.2 layer (models, ORM) | Severity: Normal | Keywords: Triage Stage: | Has patch: 0 Unreviewed | Needs documentation: 0 | Needs tests: 0 Patch needs improvement: 0 | Easy pickings: 0 UI/UX: 0 | -------------------------------------+------------------------------------- I'm using a Django management command to start a container that executes DB queries (without any transaction scope): `python manage.py <mycommand>`
These are the relevant database configs I'm using: {{{ DATABASES = { "default": env.db("DATABASE_URL"), } DATABASES["default"]["ATOMIC_REQUESTS"] = True DATABASES["default"]["CONN_HEALTH_CHECKS"] = True DATABASES["default"]["CONN_MAX_AGE"] = None ### I've also tried setting this to 0. Same issue }}} When Django loses the DB connection for whatever reason, I see the error `server closed the connection unexpectedly`, but then the error `psycopg2.InterfaceError: connection already closed` happens over and over again, every time it tries to execute a SQL query. This is very annoying because the container needs to be re-created in other for the app to function properly. Investigating this I found here that the connection health check is SKIPPED if (https://github.com/django/django/blob/main/django/db/backends/base/base.py#L576-L580): * self.connection is None; OR * self.health_checks_enabled = False; OR * self.health_check_done = True I created a test command to understand what was happening with the connection, added some logs to see the connection attributes, and found that the connection health check is always skipped because `self.health_check_done` is never set to False. **My question is:** shouldn't the connection be health checked when `self.errors_occurred` flips to True? Here's the code I used to test: {{{ import logging import time from django.core.management import BaseCommand from django.db import connection logger = logging.getLogger(__name__) class Command(BaseCommand): help = "" def handle(self, *args, **kwargs): while True: time.sleep(1) try: logger.info(f"health_check_enabled: {connection.health_check_enabled}") logger.info(f"health_check_done: {connection.health_check_done}") logger.info(f"errors_occurred: {connection.errors_occurred}") with connection.cursor() as cursor: cursor.execute("SELECT 1") logger.info("query executed") except Exception as e: logger.exception(e) }}} Here's the relevant part of the logs: {{{ health_check_enabled: False ## the connect() method was not yet called health_check_done: False ## the connect() method was not yet called errors_occurred: False query executed health_check_enabled: True health_check_done: True errors_occurred: False server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request. Traceback (most recent call last): File "/usr/local/lib/python3.11/site- packages/django/db/backends/utils.py", line 87, in _execute return self.cursor.execute(sql) ^^^^^^^^^^^^^^^^^^^^^^^^ psycopg2.OperationalError: server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request. [... Traceback omitted ...] health_check_enabled: True health_check_done: True errors_occurred: True ## This is set to True now, as expected Traceback (most recent call last): File "/usr/local/lib/python3.11/site- packages/django/db/backends/base/base.py", line 308, in _cursor return self._prepare_cursor(self.create_cursor(name)) ^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/utils/asyncio.py", line 26, in inner return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site- packages/django/db/backends/postgresql/base.py", line 330, in create_cursor cursor = self.connection.cursor() ^^^^^^^^^^^^^^^^^^^^^^^^ psycopg2.InterfaceError: connection already closed [...Traceback omitted ...] health_check_enabled: True health_check_done: True errors_occurred: True Traceback (most recent call last): File "/usr/local/lib/python3.11/site- packages/django/db/backends/base/base.py", line 308, in _cursor return self._prepare_cursor(self.create_cursor(name)) ^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/utils/asyncio.py", line 26, in inner return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site- packages/django/db/backends/postgresql/base.py", line 330, in create_cursor cursor = self.connection.cursor() ^^^^^^^^^^^^^^^^^^^^^^^^ psycopg2.InterfaceError: connection already closed [... Traceback omitted ...] health_check_enabled: True health_check_done: True errors_occurred: True Traceback (most recent call last): File "/usr/local/lib/python3.11/site- packages/django/db/backends/base/base.py", line 308, in _cursor return self._prepare_cursor(self.create_cursor(name)) ^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/utils/asyncio.py", line 26, in inner return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site- packages/django/db/backends/postgresql/base.py", line 330, in create_cursor cursor = self.connection.cursor() ^^^^^^^^^^^^^^^^^^^^^^^^ psycopg2.InterfaceError: connection already closed [... Traceback omitted ...] }}} -- Ticket URL: <https://code.djangoproject.com/ticket/34914> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/0107018b49aeb9eb-baff4e05-6438-44e2-aafc-38056258ad9c-000000%40eu-central-1.amazonses.com.