Interview answer
This is one of the most important real-world Laravel/MySQL concurrency scenarios.
Suppose inventory is:
stock = 1
Two customers simultaneously try to purchase the final item.
A naive implementation:
$product = Product::find($id);
if ($product->stock > 0) {
$product->stock--;
$product->save();
}
can suffer from a race condition because both requests may read stock = 1.
Safer approach
Use a transaction and row locking:
DB::transaction(function () use ($productId) {
$product = Product::whereKey($productId)
->lockForUpdate()
->firstOrFail();
if ($product->stock < 1) {
throw new RuntimeException('Out of stock');
}
$product->decrement('stock');
Order::create([
'product_id' => $product->id,
'quantity' => 1,
]);
});
lockForUpdate() locks the selected row until the transaction completes.
Conceptually:
Request A Request B
BEGIN BEGIN
↓ ↓
lock product waits
↓
stock = 1
↓
decrement → 0
↓
COMMIT
gets lock
↓
stock = 0
↓
reject order
Production considerations
For a real e-commerce system, I would also consider:
database transaction boundaries
row-level locking
appropriate indexes
deadlock handling/retries
idempotency for payment/order requests
order state transitions
inventory reservation versus immediate decrement
payment failures and compensation
unique constraints for duplicate order/payment requests
queue-based processing where appropriate
For example, an inventory reservation might use:
available_stock
reserved_stock
rather than immediately treating every checkout attempt as a completed sale.
0 comments:
Post a Comment
Thanks