From a1b73b5cacbcf7f7fe249fe08cc336a36d71e793 Mon Sep 17 00:00:00 2001 From: Tomer Nosrati Date: Fri, 20 Sep 2024 21:08:22 +0300 Subject: [PATCH] Resolved race condition during Redis backend teardown (#418) --- .../vendors/redis/backend/api.py | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/pytest_celery/vendors/redis/backend/api.py b/src/pytest_celery/vendors/redis/backend/api.py index d846dc77..5857adca 100644 --- a/src/pytest_celery/vendors/redis/backend/api.py +++ b/src/pytest_celery/vendors/redis/backend/api.py @@ -8,16 +8,30 @@ import gc +from celery.result import AsyncResult + from pytest_celery.api.backend import CeleryTestBackend class RedisTestBackend(CeleryTestBackend): def teardown(self) -> None: - # When a test that has a AsyncResult object is finished - # there's a race condition between the AsyncResult object - # and the Redis container. The AsyncResult object tries - # to release the connection but the Redis container has already - # exited. This causes a warning to be logged. To avoid this - # warning to our best effort we force a garbage collection here. - gc.collect(1) + """When a test that has a AsyncResult object is finished there's a race + condition between the AsyncResult object and the Redis container. + + The AsyncResult object tries to release the connection but the + Redis container has already exited. + """ + # First, force a garbage collection to clean up unreachable objects + gc.collect() + + # Next, find all live AsyncResult objects and clean them up + async_results = [obj for obj in gc.get_objects() if isinstance(obj, AsyncResult)] + + for async_result in async_results: + try: + # Remove the backend reference to prevent interaction with Redis + async_result.backend = None + except Exception: + pass + super().teardown()