#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.

Reply via email to