Use a weak reference to sqlalchemy Engine to avoid memory leak (#1771)

* Use a weak reference to sqlalchemy Engine to avoid memory leak

Closes #1761

By using a weak reference to the `Engine` object, we can avoid the memory leak as disposed `Engines` get properly deallocated. Whenever `SQLAlchemy` is uninstrumented, we only trigger a removal for those event listeners which are listening for objects that haven't been garbage-collected yet.

* Made a mistake in resolving the weak reference

* Fixed formatting issues

* Updated changelog

* Added unit test to check that engine was garbage collected

* Do not save engine in EngineTracer to avoid memory leak

* Add an empty line to satisfy black formatter

* Fix isort complaints

* Fixed the issue when pool name is not set and =None

* Fix formatting issue

* Rebased after changes in a recent commit

* Updated PR number in changelog

---------

Co-authored-by: Shalev Roda <65566801+shalevr@users.noreply.github.com>
This commit is contained in:
Rytis Bagdziunas
2023-06-27 10:37:27 +02:00
committed by GitHub
parent a45c9c3792
commit 2e49ba1af8
3 changed files with 60 additions and 18 deletions

View File

@ -307,3 +307,26 @@ class TestSqlalchemyInstrumentation(TestBase):
cnx.execute("SELECT 1 + 1;").fetchall()
spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 0)
def test_no_memory_leakage_if_engine_diposed(self):
SQLAlchemyInstrumentor().instrument()
import gc
import weakref
from sqlalchemy import create_engine
callback = mock.Mock()
def make_shortlived_engine():
engine = create_engine("sqlite:///:memory:")
# Callback will be called if engine is deallocated during garbage
# collection
weakref.finalize(engine, callback)
with engine.connect() as conn:
conn.execute("SELECT 1 + 1;").fetchall()
for _ in range(0, 5):
make_shortlived_engine()
gc.collect()
assert callback.call_count == 5