Как обеспечить синхронное увеличение двух счетчиков в асинхронной задаче 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)