Two users. One last item. One database row. And suddenly your Laravel application has a problem. π¨
Imagine your inventory says: stock = 1 Two users click Buy at almost exactly the same time.
Request A Read stock β 1
Request B Read stock β 1
Both requests think: βGreat. There is one item available.β
Then: A β decrease stock β 0 B β decrease stock β -1
Congratulations. You just sold one product twice. π
This is a classic race condition. And adding more Laravel servers doesn't fix it. In fact, distributed systems make this problem more common because multiple application instances can execute the same business logic simultaneously. So how do you prevent it?
There isn't one universal solution. The right choice depends on the operation.
1οΈβ£ Database-level atomic update Instead of: SELECT stock UPDATE stock you can make the update conditional: UPDATE products SET stock = stock - 1 WHERE id = ? AND stock > 0 Then check whether a row was actually updated. The database becomes the guard.
2οΈβ£ Database transactions + row locking For operations involving multiple related changes: BEGIN β Lock inventory row β Check stock β Create order β Decrease stock β COMMIT In Laravel: DB::transaction() + lockForUpdate() can help protect the critical section.
3οΈβ£ Distributed locks What if multiple Laravel servers are processing the same resource? You can use a distributed lock, for example with Redis: Laravel #1 β π product:123 Laravel #2 β β³ waiting Laravel #3 β β³ waiting Only one process gets to execute the critical operation at a time.
Laravel provides atomic locking primitives for this kind of coordination. But here's the important part π
A lock isn't automatically the solution. You now have new questions: What happens if the process crashes? What happens when the lock expires? How long should you wait? Can the operation safely be retried? Could you simply make the database operation atomic instead?
This is why experienced backend engineers don't start with: βWhich Laravel feature should I use?β
They start with: βWhat invariant must never be violated?β
For inventory: stock >= 0
For payments: A payment must not be charged twice.
For order creation: One request shouldn't create duplicate orders. Once you identify the invariant, the architecture becomes much easier to reason about.
That's the real system-design mindset:
Don't just protect the code. Protect the invariant.
Because at scale, the question isn't: βCan my Laravel application handle 10,000 requests?β It's: βCan 10,000 concurrent requests happen without corrupting my business state?β
That's a much harder question. And that's where backend engineering gets interesting. π₯