Interview question
Reserve Django inventory safely under concurrent requests
Uses a database transaction and row lock to keep stock non-negative when reservations race.
TL;DR
Uses a database transaction and row lock to keep stock non-negative when reservations race.
Django atomic transactions, select_for_update, invariant ownership, lock scope, rollback, and real concurrent database testing.
Practice the problem like a real interview: restate, reason, implement, and test.
Implement reserve(product_id, quantity). Two requests may reserve the same product concurrently, but committed stock must never become negative. Reject non-positive quantities and insufficient stock. Keep the lock and transaction narrow, and test the race against a database that supports row locking.
Next in Python Backend Practical Labs: SQLAlchemy keyset page
stock=5; reserve 3 and reserve 3 concurrently -> one succeeds, one fails
final stock -> 2, never -1
transaction.atomic() and read the row with select_for_update().TransactionTestCase or an equivalent real-transaction test.from django.db import transaction
class InsufficientStock(Exception):
pass
def reserve(product_id: int, quantity: int) -> int:
if quantity <= 0:
raise ValueError("quantity must be positive")
with transaction.atomic():
product = (
Product.objects
.select_for_update()
.get(pk=product_id)
)
if product.stock < quantity:
raise InsufficientStock(product.stock)
product.stock -= quantity
product.save(update_fields=["stock"])
return product.stock
The indexed row lookup is O(log n); competing reservations for one product serialize for the duration of the short transaction.
TestCase can hide transaction boundaries behind its wrapper.Spot a weak answer, missing edge case, or clearer explanation? Send it in.
Say thanks with a standalone, one-time $5 contribution. No account required.