[Answer]-Avoiding race conditions, Django + Heroku + PostgreSQL

1đź‘Ť

âś…

A simple solution would be putting the counter and winner user in the Game model. You can then use select_for_update to lock the record:

game = Game.objects.select_for_update().get(pk=gamepk)
if game.number + 1 == X
    # he is a winner
    game.winner = request.user
    game.number = game.number + 1
    game.save()

else:
    # u might need to stop the game if a winner already decided

As part of the same transaction you can also record Player s objects so you also know who clicked and track other info but don’t put the number and winner there. To use select_for_update you need to use postgresql_psycopg2 backend.

Update:
Since django set autocommit on by default, you have to wrap the above code in atomic transaction. From django docs

Select for update
If you were relying on “automatic transactions” to provide locking between select_for_update() and a subsequent >write operation — an extremely fragile design, but nonetheless possible —
you must wrap the relevant code in atomic().

You can decorate your view with @transaction.atomic:

from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # This code executes inside a transaction.
    do_stuff()
👤almalki

Leave a comment