AppEngine достигает строгой согласованности

Я пытаюсь добиться сильной согласованности. Назовем мою модель PVPPlayer:

class PVPPlayer(ndb.Model):
    points = ndb.IntegerProperty()

Каждый ключ для модели создается следующим образом:

pvp_player = PVPPlayer(key=ndb.Key(Profile, "test_id", PVPPlayer, "test_id"))

где Profile — родительская модель:

class Profile(ndb.Model):
    def build_key(cls, some_id):
        return ndb.Key(cls, some_id)

У меня есть 2 URL REST API:

1) update_points
2) get_points

In 1) I do :

# I use transaction because I have to update all the models in single batch 
@ndb.transactional(xg=True, retries=3)
def some_func(points):
    pvp_player = ndb.Key(Profile, "test_id", PVPPlayer, "test_id").get()
    pvp_player.points += points 
    pvp_player.put()
    # update other models here`

In 2) I do:

pvp_player = ndb.Key(Profile, "test_id", PVPPlayer, "test_id").get()
return pvp_player.points`

Мой поток выглядит так:

1) update_points()
2) get_points()
3) update_points()
4) get_points()`
...

Проблема:

Использование get() гарантирует строгую согласованность, поэтому я не понимаю, почему иногда в результате get_points() я получаю устаревшие данные, как будто точки вообще не обновлялись.

Пример:

POST get_points -> 0
POST sleep 1-3 sec
POST update_points -> 15
POST sleep 1-3 sec
POST get_points -> 15
POST sleep 1-3 sec
POST update_points -> 20
POST sleep 1-3 sec
POST get_points -> 15 !!!`

person Peter Leontev    schedule 25.08.2016    source источник
comment
Ваша функция № 2 также украшена @ndb.transactional? Кроме того, я предполагаю, что имя функции update_points в #1 на самом деле update_points, верно?   -  person Dan Cornilescu    schedule 25.08.2016
comment
›Ваша функция №2 также украшена @ndb.transactional? Я пытался добавить @ndb.transactional для № 2, но это не имеет значения — он все еще время от времени выдает мне устаревшие данные › имя функции update_points в № 1 действительно update_points, верно? Абсолютно   -  person Peter Leontev    schedule 25.08.2016
comment
Извините, я имел в виду some_func это update_points? :)   -  person Dan Cornilescu    schedule 25.08.2016
comment
Вы можете вызвать функцию коммита some_func. Он обновляет точки PVPPlayer и сохраняет некоторые другие модели, такие как PVPMatch (some_func может работать максимум с 3 группами объектов), но я обновляю модель PVPPlayer только один раз в этом запросе.   -  person Peter Leontev    schedule 25.08.2016


Ответы (2)


Есть ли случай, когда вы превышаете ограничение на запись для каждой группы сущностей, то есть одно обновление в секунду? Я думаю, что это может нарушить сильную согласованность группы сущностей, как указано в документации.

person Konstantinos G    schedule 25.08.2016
comment
Физический игрок — единственный, кто обновляет модель PVPPlayer. Ситуация, когда кто-то делает 2 запроса update_points() одновременно для одной и той же модели, по игровой логике вообще произойти не может. - person Peter Leontev; 25.08.2016
comment
На самом деле, что еще более странно, так это то, что иногда между двумя последовательными update_points() есть 15-20-секундный разрыв, но данные все еще устарели, поэтому они ведут себя точно так же, как возможная согласованность, но я не могу понять, почему - person Peter Leontev; 25.08.2016

Сначала проверьте свои журналы, одно из обновлений должно завершиться с ошибкой, потому что ваша логика в основном верна.

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


Этот случай, вероятно, связан не с проблемами согласованности, а с топанием обновлений, проверьте эти ссылки для некоторых интересных случаев:

http://engineering.khanacademy.org/posts/transaction-safety.htm http://engineering.khanacademy.org/posts/user-write-lock.htm

person glmvrml    schedule 26.08.2016
comment
Я только что понял, что один из моих запросов обновляет мою родительскую модель (то есть профиль) одновременно с update_points(). Это похоже на проблему - person Peter Leontev; 26.08.2016
comment
Должен ли я назначать другой родительский ключ, чтобы избежать этой проблемы? - person Peter Leontev; 26.08.2016
comment
Все, что имеет общий родительский ключ, включая родителя, находится в одной группе сущностей. - person Tim Hoffman; 26.08.2016
comment
@PeterLeontev заключает все ваши обновления в транзакции, чтобы избежать условий гонки - person glmvrml; 26.08.2016