From 26afb84415e43548fd10637546165178b4c09d19 Mon Sep 17 00:00:00 2001 From: Wai Lee Chin Feman Date: Tue, 23 Jul 2024 13:10:00 -0400 Subject: [PATCH 1/4] Demo the deadlock --- tests/test_bulk_update_models.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/tests/test_bulk_update_models.py b/tests/test_bulk_update_models.py index 9c980ba..608b80a 100644 --- a/tests/test_bulk_update_models.py +++ b/tests/test_bulk_update_models.py @@ -1,21 +1,34 @@ from datetime import datetime, timezone -from django.test import TestCase +from django.test import TestCase, TransactionTestCase from django_bulk_load import bulk_update_models, generate_greater_than_condition from .test_project.models import ( TestComplexModel, TestForeignKeyModel, ) +import random +import threading +def do_update(): + objects = [x for x in TestComplexModel.objects.all()] + for current in objects: + current.integer_field = random.randint(10,100000) + bulk_update_models(objects) -class E2ETestBulkUpdateModels(TestCase): +class E2ETestBulkUpdateModels(TransactionTestCase): def test_integer_field_change(self): - model1 = TestComplexModel(integer_field=1) - model1.save() - model1.integer_field = 2 - bulk_update_models([model1]) - saved_model = TestComplexModel.objects.get() - self.assertEqual(saved_model.integer_field, 2) + models = [TestComplexModel(integer_field=1) for x in range(10000)] + for model in models: + model.save() + threads = [ + threading.Thread(target=do_update) + for x in range(80) + ] + for t in threads: + t.start() + for t in threads: + t.join() + print("JOINED") def test_string_field_change(self): model1 = TestComplexModel(string_field="hello") From 45775c6dfaef5e013b71fe361b44f00089a18940 Mon Sep 17 00:00:00 2001 From: Wai Lee Chin Feman Date: Tue, 23 Jul 2024 13:16:54 -0400 Subject: [PATCH 2/4] Hack a fix in, to see if it helps (it does) --- django_bulk_load/bulk_load.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/django_bulk_load/bulk_load.py b/django_bulk_load/bulk_load.py index 296b34d..9ec44e0 100644 --- a/django_bulk_load/bulk_load.py +++ b/django_bulk_load/bulk_load.py @@ -301,6 +301,8 @@ def bulk_update_models( else: queries = [update_query] + helper = f"select id from {table_name} order by id asc for update" + queries = [helper] + queries return bulk_load_models_with_queries( models=models, loading_table_name=loading_table_name, From f59eddd7d6bedbe9d2bfff7f4dac4f0d0faa05a3 Mon Sep 17 00:00:00 2001 From: Wai Lee Chin Feman Date: Tue, 23 Jul 2024 13:58:28 -0400 Subject: [PATCH 3/4] Clean up test output --- tests/test_bulk_update_models.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/test_bulk_update_models.py b/tests/test_bulk_update_models.py index 608b80a..6264833 100644 --- a/tests/test_bulk_update_models.py +++ b/tests/test_bulk_update_models.py @@ -2,33 +2,42 @@ from django.test import TestCase, TransactionTestCase from django_bulk_load import bulk_update_models, generate_greater_than_condition +import queue from .test_project.models import ( TestComplexModel, TestForeignKeyModel, ) import random import threading +import sys -def do_update(): +def do_update(bucket): objects = [x for x in TestComplexModel.objects.all()] for current in objects: current.integer_field = random.randint(10,100000) - bulk_update_models(objects) + try: + bulk_update_models(objects) + except Exception: + bucket.put(sys.exc_info()) class E2ETestBulkUpdateModels(TransactionTestCase): def test_integer_field_change(self): models = [TestComplexModel(integer_field=1) for x in range(10000)] + error_bucket = queue.Queue() + for model in models: model.save() threads = [ - threading.Thread(target=do_update) + threading.Thread(target=do_update, args=[error_bucket]) for x in range(80) ] for t in threads: t.start() for t in threads: t.join() - print("JOINED") + while not error_bucket.empty(): + raise error_bucket.get()[1] + def test_string_field_change(self): model1 = TestComplexModel(string_field="hello") From dc8756265ae9c7436d38051ebd8b3bbbf04773e3 Mon Sep 17 00:00:00 2001 From: Wai Lee Chin Feman Date: Tue, 23 Jul 2024 14:02:17 -0400 Subject: [PATCH 4/4] Clean up test output --- tests/test_bulk_update_models.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_bulk_update_models.py b/tests/test_bulk_update_models.py index 6264833..07cb4e0 100644 --- a/tests/test_bulk_update_models.py +++ b/tests/test_bulk_update_models.py @@ -1,5 +1,6 @@ from datetime import datetime, timezone +from django.db import close_old_connections from django.test import TestCase, TransactionTestCase from django_bulk_load import bulk_update_models, generate_greater_than_condition import queue @@ -19,6 +20,7 @@ def do_update(bucket): bulk_update_models(objects) except Exception: bucket.put(sys.exc_info()) + close_old_connections() class E2ETestBulkUpdateModels(TransactionTestCase): def test_integer_field_change(self): @@ -29,7 +31,7 @@ def test_integer_field_change(self): model.save() threads = [ threading.Thread(target=do_update, args=[error_bucket]) - for x in range(80) + for x in range(40) ] for t in threads: t.start()