AppEngine: keeping DataStore consistent when creating records

I hit a little dilemma! I have a handler called a vote; when he is called, he selects the user for what they have chosen. In order to remember which parameters they selected earlier, I save the VoteRecord parameters, which determine which of their current voting is set.

Of course, the first time they vote, I need to create an object and save it. But consistent voices should simply change the value of an existing VoteRecord. But he has a problem: in some circumstances, two VoteRecords can be created. This is rare (only once in all 500 votes that we have seen so far), but still bad when this happens.

The problem arises because two separate handlers do this essentially:

query = VoteRecord.all().filter('user =', session.user).filter('poll =', poll)

if query.count(1) > 0:
 vote = query[0]

 poll.votes[vote.option] -= 1
 poll.votes[option] += 1
 poll.put()

 vote.option = option
 vote.updated = datetime.now()
 vote.put()
else:
 vote = VoteRecord()
 vote.user = session.user
 vote.poll = poll
 vote.option = option
 vote.put()

 poll.votes[option] += 1
 poll.put()

 session.user.votes += 1
 session.user.xp += 3
 session.user.put()

 incr('votes')

My question is: what is the most efficient and fastest way to handle these requests, ensuring that no request is lost and no request creates two VoteRecord objects?

+3
source share
2 answers

The problem is this part:

if vote.count(1) == 0:
    obj = VoteRecord()
    obj.user = user
    obj.option = option
    obj.put()

Without a transaction, your code could work in this order in two instances of the interpreter:

if vote.count(1) == 0:
    obj = VoteRecord()
    obj.user = user


if vote.count(1) == 0:
    obj = VoteRecord()
    obj.user = user
    obj.option = option
    obj.put()


    obj.option = option
    obj.put()

Or any strange combination of them. The problem is that the test counter starts again before the start, so the second thread goes through the first part of the conditional expression instead of the second.

, ,

db.run_in_transaction()

.

, , , , , . / Google , , . , . -, , .

, . :

def checkAndLockPage(pageKey):
  page = db.get(pageKey)
  if page.locked:
    return False
  else:
    page.locked = True
    page.put()
    return True

, .

+1

- Model.get_or_insert. -, - - , get_or_insert :

vote = VoteRecord.get_or_insert(pollname, parent=session.user, user=session.user, poll=poll, option=option)
if vote.option != option:
  # Record already existed; we need to update it
  vote.option = option
  vote.put()
+3

Source: https://habr.com/ru/post/1702849/


All Articles