Skip to content

Commit

Permalink
Merge pull request #375 from GateNLP/issue-374
Browse files Browse the repository at this point in the history
User-level DB lock in get_annotator_task to avoid race condition
  • Loading branch information
twinkarma committed May 22, 2023
2 parents 9b95730 + 89d0cd5 commit c78be97
Showing 1 changed file with 10 additions and 0 deletions.
10 changes: 10 additions & 0 deletions backend/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ class ServiceUser(AbstractUser):
agreed_privacy_policy = models.BooleanField(default=False)
is_deleted = models.BooleanField(default=False)

def lock_user(self):
"""
Lock this user with a SELECT FOR UPDATE. This method must be called within a transaction,
the lock will be released when the transaction commits or rolls back.
"""
return type(self).objects.filter(id=self.id).select_for_update().get()

@property
def has_active_project(self):
return self.annotatorproject_set.filter(status=AnnotatorProject.ACTIVE).count() > 0
Expand Down Expand Up @@ -592,6 +599,9 @@ def get_annotator_task(self, user):
user from annotator list if there's no more tasks or user reached quota.
"""

# Lock required to prevent concurrent calls from assigning two different tasks
# to the same user
user = user.lock_user()
annotation = self.get_current_annotator_task(user)
if annotation:
# User has existing task
Expand Down

0 comments on commit c78be97

Please sign in to comment.