0

I have these following models, even though I used select_for_update in the aggregation, I'm still encountering race condition in this withdraw method :

How do I lock the entries until withdraw() method finished?

class BalanceHandler():
    @atomic
    def withdraw(account, amount):
        # race condition happened here where multiple withdrawals happenning concurrently
        # can't use entries.select_for_update().get_total() because it's not available for QuerySet
        if account.entries.get_total() < amount:
            raise Exception("not enough balance")            
         # do something with the amount


 class LedgerEntry(models.Model):
    amount = models.DecimalField(max_digits=18, decimal_places=6)
    ledger_account = models.ForeignKey(LedgerAccount, related_name='entries')

class LedgerEntryManager(models.Manager):
    def get_total(account, *args, **kwargs):
        return self.select_for_update().filter(*args, **kwargs).aggregate(Sum('amount'))['amount__sum']

class LedgerAccount(models.Model):
    account_number = models.CharField(max_length=20, editable=False)

Note: I found this question ( How to prevent race condition in Django on INSERT with limiting SUM?) but in that case, OP was able to lock the master object (project). In my case, how do I lock the LedgerAccount object during withdraw() or get_total()?

Dio Phung
  • 5,944
  • 5
  • 37
  • 55
  • Why don't you add `with transaction.atomic():` or decorator immediate after function start? or decorator to `@transation.atomic` before line `def withdraw(account, amount)`: ? Or you can also implement custom transactions https://docs.djangoproject.com/en/1.11/topics/db/transactions/#django.db.transaction.clean_savepoints – Anup Yadav Feb 23 '18 at 06:06
  • https://medium.com/@hakibenita/how-to-manage-concurrency-in-django-models-b240fed4ee2 https://stackoverflow.com/questions/1645269/concurrency-control-in-django-model https://stackoverflow.com/questions/320096/django-how-can-i-protect-against-concurrent-modification-of-database-entries – Anup Yadav Feb 23 '18 at 06:17
  • @AnupYadav : I did use the atomic decorator, updated the code to show that fact. Hope I made it clearer. – Dio Phung Feb 26 '18 at 17:24

0 Answers0