Запросы на синхронизацию на нескольких серверах

У нас есть API для игры на Django Rest Framework. В игре есть турниры и участники турниров. Модель турнира имеет поле max_players и API не должен позволять регистрировать больше участников, когда число max_players достигнуто.

Это упрощенные модели:

class Tournament(models.Model):
    max_players = models.PositiveIntegerField()

class TourneyPlayer(models.Model):
    tourney = models.ForeignKey(Tourney, on_delete=models.CASCADE, related_name='players')
    user = models.ForeignKey(User, on_delete=models.CASCADE)

В конечной точке регистрации установлен сериализатор, который в своем методе validate проверяет количество уже зарегистрированных игроков и возвращает ошибку, если турнир переполнен:

def validate(self, attrs):
    if tourney.players.count() >= tourney.max_players:
        raise serializers.ValidationError()
    return attrs

Если проверка пройдена, мы создаем новый объект TourneyPlayer.

Но когда мы создаем новый турнир, все пользователи получают уведомление, и многие из них сразу же нажимают на кнопку регистрации. Это приводит к большому количеству одновременных запросов, и иногда игрок регистрируется даже тогда, когда счетчик max_player достигнут. Это происходит потому, что существует некоторая задержка между проверкой и созданием, поэтому возникает классическая проблема параллелизма:

Запрос A подтвержден Запрос B подтвержден Запрос A создал игрока Запрос B создал игрока

Локально я решил эту проблему, добавив объект threading.Lock, но как это сделать, если у нас несколько серверов за балансировщиком нагрузки? Я думаю использовать Redis, записывать некоторое значение, когда начинается запрос на регистрацию, и очищать это значение, когда он завершается. А если значение уже установлено, проверять его в цикле с некоторым интервалом, используя функцию sleep. Но может быть есть решения получше?

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