🔒 When Your Database Gets Stuck: Understanding Deadlocks

ruby dev.to

Have you ever seen an application suddenly fail with something like:
“Deadlock detected”?
Your code may look perfectly fine.
Your database may be healthy.
But two transactions can still end up waiting for each other forever.

💥 What is a Database Deadlock?

Imagine two Rails transactions:
Transaction A locks → User #1
Then waits for → User #2

At the same time:
Transaction B locks → User #2
Then waits for → User #1

Now:
🔴 A is waiting for B
🔴 B is waiting for A
Nobody can continue.
That's a deadlock.

🚂 How can Ruby on rails applications avoid it?
1️⃣ Lock records in the same order
If multiple transactions need the same records, always acquire locks in a consistent order.

User.transaction do
 users = User
 .where(id: [user_a_id, user_b_id])
 .order(:id)
 .lock

 # Update users...
end
Enter fullscreen mode Exit fullscreen mode

Instead of one process locking:
User 1 → User 2
while another locks:
User 2 → User 1
make both follow:
User 1 → User 2
This dramatically reduces deadlock risk.

2️⃣ Keep transactions short
Avoid doing unnecessary work inside a transaction.
❌ API calls
❌ Long calculations
❌ File processing
❌ External services
Do only the database work that needs to be atomic.

3️⃣ Be careful with nested/related updates
Updating multiple tables or records inside different transactions can create unexpected lock dependencies.
Understand which records your transaction locks and in what order.

4️⃣ Retry when appropriate
Deadlocks can still happen in highly concurrent systems.
Rails supports transaction retry patterns, but don't blindly retry everything.

A retry should be:
✅ Limited
✅ Idempotent
✅ Used for transient database failures

🎯 The Golden Rule
Deadlocks aren't simply a database problem.
They're often a concurrency and transaction-design problem.
When building a Rails application, ask:
What does this transaction lock, and in what order?
That simple question can prevent some very painful production incidents.

Source: dev.to

arrow_back Back to Tutorials