You: "If the code reads the stock in Python, checks it and then saves, we get a lost update and overselling.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # ====================================================================== # Q: CTO: "Two customers buy the last product at the same time. What happens in # your system?" # # You: "If the code reads the stock in Python, checks it and then saves, we get # a lost update and overselling. I let the database guarantee it with a # conditional atomic UPDATE: if 0 rows are affected, the product is sold out and # the second user sees a friendly message. As a safety net I have a # CheckConstraint so the stock can never become negative. If the flow is more # complex (multiple products, coupons), I lock with select_for_update in a fixed # order." Chapter 4. # ====================================================================== def reserve(product_id, qty): updated = (Product.objects .filter(pk=product_id, stock__gte=qty) .update(stock=F('stock') - qty)) if not updated: raise OutOfStock(product_id) class Product(models.Model): stock = models.IntegerField() class Meta: constraints = [models.CheckConstraint( condition=Q(stock__gte=0), name='product_stock_non_negative')] |