Best approach to concurrency handling in Django for eauction toy-app

I am using a game application for playing Django and am confused about how best to handle concurrency in the code below. I'm not sure which of my solution candidates (or any other) is best for Django design. I am new to Django / python and my SQL know-how is rusty, so apologize if this is not a problem.

Requirement: Users can bid on products. Offers are accepted only if they are higher than previous bids on the same product.

Here is a stripped down version of the models:

class Product(models.Model): name = models.CharField(max_length=20) class Bid(models.Model): amount = models.DecimalField(max_digits=5, decimal_places=2) product = models.ForeignKey(Product) 

and type of application. Here are the conditions of the race (see comments):

 def bid(request, product_id): p = get_object_or_404(Product, pk=product_id) form = BidForm(request.POST) if form.is_valid(): amount = form.cleaned_data['amount'] # the following code is subject to race conditions highest_bid_amount = Bid.objects.filter(product=product_id).aggregate(Max('amount')).get('amount__max') # race condition: a bid might have been inserted just now by another thread so highest_bid_amount is already out of date if (amount > highest_bid_amount): bid = Bid(amount=amount, product_id=product_id) # race condition: another user might have just bid on the same product with a higher amount so the save() below is incorrect b.save() return HttpResponseRedirect(reverse('views.successul_bid)' 

Applicants to the decisions I have reviewed so far:

  • I read the Django transaction document, but donโ€™t know how to apply them to my problem. Since the database does not know about the requirement of increasing rates, it cannot force Django to throw an IntegrityError. Is there a way to define this constraint during model definition? Or did he misunderstand the transaction API?
  • A stored procedure can take care of the bid logic. This seems like the โ€œbestโ€ choice for me, but it switches the race status processing to the underlying database system. If this is a good approach, can this solution be combined with solution 1?
  • I considered using the select_for_update call to block bids for this product. However, this does not seem like a solution, because, in my opinion, it will not affect the creation of new bets?

The wish list:

  • If possible, I would like to refrain from blocking the entire betting table, since bets on other products cannot be affected in any way.
  • If there is a good solution at the application level, I would like the code not to depend on the underlying database system.

Thanks so much for your thoughts!

+4
source share
2 answers

Have you checked Celery ? You can process your requests asynchronously, request queues, and then send results or errors when they are available. This seems like a likely path if you want to avoid blocking.

Otherwise, it seems that some kind of blocking should happen.

0
source

Is it possible to add the highest_bid column to Products . If my logic is not turned off, you can update the highest bid where product_id = x and highest < current_bid . If this query indicates that the row has been updated, you add a new entry to the bid table. This probably means that you will need to have a default value for the high_bid column.

0
source

All Articles