Как обеспечить синхронное увеличение двух счетчиков в асинхронной задаче Celery

Я столкнулся со сценарием, когда одна конечная точка получает несколько одновременных запросов на загрузку изображений. После успешной загрузки необходимо синхронно увеличить два счетчика. Изначально я пробовал синхронно увеличивать счетчики, но из-за условий гонки результаты были неверными. Поэтому я реализовал асинхронную задачу Celery, чтобы справиться с этой задачей. Однако в то время как один счетчик остается синхронизированным, другой - нет. Я недоумеваю, почему только один счетчик подвержен влиянию, если оба подвергаются одинаковым условиям. В качестве базы данных я использую Postgres.

Для решения проблемы асинхронного увеличения счетчика одним из возможных решений является полное удаление счетчиков и отслеживание количества загруженных изображений или использование блокировки таблицы с помощью select_for_update. Однако очень важно понять первопричину асинхронного поведения, чтобы предотвратить подобные проблемы в будущем.

Это часть кода, которая выполняет инкремент

@shared_task
def increment_album_and_event_image_count(album_id):
    try:
        with transaction.atomic():
            album = Album.objects.get(id=album_id)
            album.image_count_in_album = F("image_count_in_album") + 1
            album.save()
            album.event.number_of_images_across_albums = (
                F("number_of_images_across_albums") + 1
            )
            album.event.save()
        return True
    except Exception as e:
        logger.error(f"Error incrementing image count: {e}, album: {album}")
        return False

Здесь число_изображений_в_альбомах содержит корректную информацию, а число_изображений_в_альбомах - нет.

Вот подробная информация о модели:

class Album(TimeStampedModel):
    image_count_in_album = models.IntegerField(default=0)
    event = models.ForeignKey("Event", on_delete=models.CASCADE)
class Event(TimeStampedModel):
    number_of_images_across_albums = models.IntegerField(default=0)

Вернуться на верх