We are working to build an exchange using Go. Following components are there in the system of now:
- Frontend
- Backend
- Matching Engine.
Here is how the system works:
- User creates an order which goes to Backend.
- Backend processes the new order in following manner :
- It validates the order request data & then a db transaction is created for updating users account balance in account table & new order is inserted in the order table.
- After db interaction is completed; backend produces a new order message in queue.
 
- Matching Engine processes the new order from the queue and pushes the engine response(i.e updated orders & trades) in another queue
- Backend consumes the engine response as below: - Multiple goroutines run in parallel to process engine response &store the updates received in engine response.
- For storing the the updates, a database transaction is created within each goroutine to update the users account balance, orders & store new trades.
 
- Problem occurs during this stage when concurrent (parallel) transactions try to update the same users account at a time, a deadlock is created in DB as multiple transaction try to lock the same record. Also while a users previously placed orders are being matched and processed user can create new order as mentioned in step 2, so transaction created in step 2 also tries to update the same users account in database which is being accessed by backend to store Matching Engine response. This also adds to the chances of deadlock. 
- How to properly manage and prevent the database deadlock generated in above mentioned flow. 
- We have tried a solution to retry transaction by following code but the deadlock issue can still be reproduced 
    // Update accounts, orders, trades with max retry of 5
    for i := 0; i < 5; i++ {
        err = nil
        time.Sleep(10 * time.Second)
        if err = manager.saveEngineResponse(newEngineResponse, accountUpdatesToDoRef, &updatedOrders); err == nil {
            break
        }
        logger.Debug("Error saving engine response", err)
    }
    if err != nil {
        logger.Fatal(err)
        return
    }
Error : Error 1213: Deadlock found when trying to get lock; try restarting transaction
I have refered the link : How to avoid mysql 'Deadlock found when trying to get lock; try restarting transaction' which states that by keeping the operations in a specific order deadlocks can be avoided. And in the above scenario all transaction will first update account, then order & then trades if any. So the order of operations is consistent in different transactions
