From d53ac20f9f3be9fc8020b942e2a5a87a7296cb3f Mon Sep 17 00:00:00 2001 From: Marcel Canu Date: Thu, 12 Dec 2024 11:24:27 -0300 Subject: [PATCH 1/2] Using select_for_update to grab a lock when calculating inner_id --- label_studio/tasks/serializers.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/label_studio/tasks/serializers.py b/label_studio/tasks/serializers.py index 6fc612ce5a5b..fe2406142fdd 100644 --- a/label_studio/tasks/serializers.py +++ b/label_studio/tasks/serializers.py @@ -533,10 +533,13 @@ def add_tasks(self, task_annotations, task_predictions, validated_tasks): db_tasks = [] max_overlap = self.project.maximum_annotations - # identify max inner id - tasks = Task.objects.filter(project=self.project) - prev_inner_id = tasks.order_by('-inner_id')[0].inner_id if tasks else 0 + # Acquire a lock on the project to ensure atomicity when calculating inner_id + project = Project.objects.select_for_update().get(id=self.project.id) + + last_task = Task.objects.filter(project=project).order_by('-inner_id').first() + prev_inner_id = last_task.inner_id if last_task else 0 max_inner_id = (prev_inner_id + 1) if prev_inner_id else 1 + for i, task in enumerate(validated_tasks): cancelled_annotations = len([ann for ann in task_annotations[i] if ann.get('was_cancelled', False)]) total_annotations = len(task_annotations[i]) - cancelled_annotations From 7a8fc6a07316e4791895939f7e38c1498ebed10b Mon Sep 17 00:00:00 2001 From: Marcel Canu Date: Wed, 18 Dec 2024 13:45:12 -0300 Subject: [PATCH 2/2] Using fast_first --- label_studio/tasks/serializers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/label_studio/tasks/serializers.py b/label_studio/tasks/serializers.py index fe2406142fdd..1ec5c5f74535 100644 --- a/label_studio/tasks/serializers.py +++ b/label_studio/tasks/serializers.py @@ -6,6 +6,7 @@ from core.feature_flags import flag_set from core.label_config import replace_task_data_undefined_with_config_field from core.utils.common import load_func, retry_database_locked +from core.utils.db import fast_first from django.conf import settings from django.db import IntegrityError, transaction from drf_yasg import openapi @@ -536,7 +537,7 @@ def add_tasks(self, task_annotations, task_predictions, validated_tasks): # Acquire a lock on the project to ensure atomicity when calculating inner_id project = Project.objects.select_for_update().get(id=self.project.id) - last_task = Task.objects.filter(project=project).order_by('-inner_id').first() + last_task = fast_first(Task.objects.filter(project=project).order_by('-inner_id')) prev_inner_id = last_task.inner_id if last_task else 0 max_inner_id = (prev_inner_id + 1) if prev_inner_id else 1