From ff818f3c959c782c57b6a7a07d6b0158550613f0 Mon Sep 17 00:00:00 2001 From: Dan LaManna Date: Fri, 4 Oct 2024 13:07:14 -0400 Subject: [PATCH] Fix exception handling in publishing transaction --- isic/core/models/isic_id.py | 24 +++++++++++++++++------- isic/ingest/services/cohort/__init__.py | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/isic/core/models/isic_id.py b/isic/core/models/isic_id.py index 6089ac81..27ec5cb8 100644 --- a/isic/core/models/isic_id.py +++ b/isic/core/models/isic_id.py @@ -2,19 +2,29 @@ from django.core.validators import RegexValidator from django.db import IntegrityError, models -from tenacity import retry, retry_if_exception_type, stop_after_attempt from isic.core.constants import ISIC_ID_REGEX class IsicIdManager(models.Manager): - @retry( - reraise=True, - retry=retry_if_exception_type(IntegrityError), - stop=stop_after_attempt(10), - ) def create_random(self): - return self.create(id=f"ISIC_{secrets.randbelow(9999999):07}") + """ + Create a random unused ISIC ID. + + Note that this is prone to race conditions. The actual creation should be wrapped + in a call to lock_table_for_writes(IsicId). + """ + obj = None + for _ in range(10): + isic_id = f"ISIC_{secrets.randbelow(9999999):07}" + if not self.filter(pk=isic_id).exists(): + obj = self.create(pk=isic_id) + break + + if obj is None: + raise IntegrityError("Failed to create a unique ISIC ID") + + return obj class IsicId(models.Model): diff --git a/isic/ingest/services/cohort/__init__.py b/isic/ingest/services/cohort/__init__.py index 44068bf9..dd4aa069 100644 --- a/isic/ingest/services/cohort/__init__.py +++ b/isic/ingest/services/cohort/__init__.py @@ -57,7 +57,7 @@ def cohort_publish( ) # this creates a transaction - with lock_table_for_writes(IsicId), cachalot_disabled(): + with lock_table_for_writes(IsicId), cachalot_disabled(), transaction.atomic(): for accession in cohort.accessions.publishable().iterator(): image = image_create(creator=publisher, accession=accession, public=public) collection_add_images(collection=cohort.collection, image=image, ignore_lock=True)