Possible Django/psycopg2 regression in 1.39.1
How do you use Sentry?
Sentry Saas (sentry.io)
Version
1.39.1
Steps to Reproduce
We have a complex dynamic multi-DB Django setup. For unit testing it, we use a custom Pytest plugin that creates and destroys databases dynamically. I noticed, the following code executed on Pytest teardown causes a problem for the sentry-sdk 1.39.1 Python module:
from django.db import connections
# ...
default_conn = connections["default"]
default_conn.close()
default_conn.connect()
The issue does not exist in version 1.39.0, so I believe it is caused by commit d76fa983329610314c9c105df2fc88278d149db0.
The Django version is 3.2.23, running in uwsgi 2.0.23 on Python 3.10.13. The version of psycopg2 is 2.9.9.
The Sentry integration is configured in Django's settings.py:
from sentry_sdk.integrations.celery import CeleryIntegration
from sentry_sdk.integrations.django import DjangoIntegration
from sentry_sdk.integrations.logging import LoggingIntegration
from sentry_sdk.integrations.redis import RedisIntegration
# ...
sentry_sdk.init(
dsn=SENTRY_DSN,
integrations=[
LoggingIntegration(event_level=logging.WARNING),
DjangoIntegration(),
CeleryIntegration(),
RedisIntegration(),
],
send_default_pii=True,
release=BUILD_VERSION,
server_name=SERVER_NAME,
)
Expected Result
The expected result is Django re-opening the default DB connection without any problems.
Actual Result
sentry-sdk crashes with the following exception:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
src/sfx_common/tests/pytest_multi_db.py:334: in force_drop_db
default_conn.connect()
/pyroot/lib/python3.10/site-packages/sentry_sdk/integrations/django/__init__.py:676: in connect
_set_db_data(span, self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
span = <Span(op='db', description:'connect', trace_id='efb49a9eeb044b738767c28a03df97cd', span_id='909de08a2b0ad436', parent_span_id=None, sam
pled=None)>
cursor_or_db = <django.contrib.gis.db.backends.postgis.base.DatabaseWrapper object at 0x7f516b24c730>
def _set_db_data(span, cursor_or_db):
# type: (Span, Any) -> None
db = cursor_or_db.db if hasattr(cursor_or_db, "db") else cursor_or_db
vendor = db.vendor
span.set_data(SPANDATA.DB_SYSTEM, vendor)
# Some custom backends override `__getattr__`, making it look like `cursor_or_db`
# actually has a `connection` and the `connection` has a `get_dsn_parameters`
# attribute, only to throw an error once you actually want to call it.
# Hence the `inspect` check whether `get_dsn_parameters` is an actual callable
# function.
is_psycopg2 = (
hasattr(cursor_or_db, "connection")
and hasattr(cursor_or_db.connection, "get_dsn_parameters")
and inspect.isroutine(cursor_or_db.connection.get_dsn_parameters)
)
if is_psycopg2:
> connection_params = cursor_or_db.connection.get_dsn_parameters()
E psycopg2.InterfaceError: connection already closed
/pyroot/lib/python3.10/site-packages/sentry_sdk/integrations/django/__init__.py:703: InterfaceError
Hey @vakorol Thanks for reporting this and the good description of the problem. We will look into this.
This does not seem to be an issue anymore with sentry-sdk==2.13.0. Closing.