Sitemap

Deadlock in E-commerce Solution by Lock Ordering

3 min readOct 14, 2024

--

Deadlock Problem: Ordering Products in Different Sequences

In an e-commerce application, when multiple users are placing orders for multiple products, deadlocks can occur if the transactions lock product rows in different sequences.

Scenario:

  • Transaction A locks Product 1 first, then Product 2.
  • Transaction B locks Product 2 first, then Product 1.

This leads to a deadlock situation:

  • Transaction A holds the lock on Product 1 and waits for Product 2.
  • Transaction B holds the lock on Product 2 and waits for Product 1.
  • Neither transaction can proceed, and they are stuck in a cyclic wait, causing a deadlock.

Problem Code Example:

Here’s the problematic code where each transaction locks products in the order provided:

async function orderProducts(req, res) {
const { userId, productIds } = req.body; // Array of product IDs

const transaction = await sequelize.transaction();

try {
// Lock the products in the order provided by the user
for (const productId of productIds) {
await Inventory.findOne({
where: { productId },
lock: transaction.LOCK.UPDATE,
transaction,
});
}

// Process the order for each product
for (const productId of productIds) {
await Order.create({
userId,
productId,
quantity: 1,
}, { transaction });
}

// Commit the transaction
await transaction.commit();
res.json({ message: 'Order completed successfully' });
} catch (error) {
await transaction.rollback();
res.status(500).json({ error: error.message });
}
}

In this code, if Transaction A processes productIds as [1, 2] and Transaction B processes productIds as [2, 1], a deadlock will occur because they are locking the same resources (products) in a different order.

Solution: Sorting Products by ID to Prevent Deadlock

To solve this issue, we ensure that all transactions always lock the products in a consistent order — by sorting the products by their IDs before locking them. This prevents deadlocks because both transactions will try to lock the products in the same sequence, avoiding cyclic waiting.

Solution Code:

// Helper function to sort product IDs
function sortProductsById(productIds) {
return productIds.sort((a, b) => a - b); // Sort in ascending order
}

async function orderProducts(req, res) {
const { userId, productIds } = req.body; // Array of product IDs

// Always lock products in ascending order of their IDs
const sortedProductIds = sortProductsById(productIds);

const transaction = await sequelize.transaction();

try {
// Lock the products based on sorted IDs
for (const productId of sortedProductIds) {
await Inventory.findOne({
where: { productId },
lock: transaction.LOCK.UPDATE,
transaction,
});
}

// Process the order for each product
for (const productId of sortedProductIds) {
await Order.create({
userId,
productId,
quantity: 1,
}, { transaction });
}

// Commit the transaction
await transaction.commit();
res.json({ message: 'Order completed successfully' });
} catch (error) {
await transaction.rollback();
res.status(500).json({ error: error.message });
}
}

How the Solution Works:

  1. Sorting Products: The sortProductsById function ensures that the product IDs are always sorted in ascending order before locking them. This means all transactions will lock Product 1 first, then Product 2, avoiding any inconsistent locking order.
  2. Locking Consistency: Whether it’s Transaction A or Transaction B, they will now lock products in the same sequence, avoiding cyclic waiting between locks.
  3. Order Processing: After locking all products in a consistent order, the order processing happens without any risk of deadlock.

Why This Solves the Problem:

By always locking resources in a consistent order, you eliminate the possibility of transactions waiting on each other in different orders. This ensures that:

  • Transaction A and Transaction B will always lock Product 1 first, then Product 2, ensuring no cyclic wait and no deadlock.

In real-world applications, this technique can be applied wherever multiple resources need to be locked within a transaction.

--

--

Aditya Yadav
Aditya Yadav

Written by Aditya Yadav

Software Engineer who talks about tech concepts in web development https://www.linkedin.com/in/aditya-yadav-01/