Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hook available for automatic retry after deadlock in django and mysql setup

I am using innoDB table in Django with mysql database. During investigation of error

OperationalError: (1213, 'Deadlock found when trying to get lock; try restarting transaction')

I came across this answer from Omry. In last part of the answer he suggests

the client should retry automatically.

I am trying to put this logic in code but at the same time is there any hook directly available in django. So that we can set 3 time automate retry in case of deadlock. Also if anyone can give example of putting this logic in code (I'm using django filters).

PS: I could have asked this below Omry's answer but I'm below 50 points and also wanted to bring it to the django experts.

like image 496
rajalokan Avatar asked Jun 19 '13 05:06

rajalokan


People also ask

How do you fix deadlock found when trying to get lock try restarting transaction?

To avoid deadlock, you must then make sure that concurrent transactions don't update row in an order that could result in a deadlock. Generally speaking, try to acquire lock always in the same order even in different transaction (e.g. always table A first, then table B).

How do I stop deadlocks in MySQL?

Just try again. Keep transactions small and short in duration to make them less prone to collision. Commit transactions immediately after making a set of related changes to make them less prone to collision. In particular, do not leave an interactive mysql session open for a long time with an uncommitted transaction.

What causes MySQL deadlock?

A deadlock in MySQL happens when two or more transactions mutually hold and request for locks, creating a cycle of dependencies. In a transaction system, deadlocks are a fact of life and not completely avoidable.

What is deadlock found when trying to get lock?

Deadlock happens when different concurrent transactions are unable to proceed because each one holds a lock that the other needs.


1 Answers

This is an old question but since nobody posted an answer, here it is.

In order to retry queries if a deadlock happens, what I did was I monkey patched the method "execute" of django's CursorWrapper class. This method is called whenever a query is made, so it will work across the entire ORM and you won't have to worry about deadlocks across your project:

import django.db.backends.utils
from django.db import OperationalError
import time

original = django.db.backends.utils.CursorWrapper.execute

def execute_wrapper(*args, **kwargs):
    attempts = 0
    while attempts < 3:
        try:
            return original(*args, **kwargs)
        except OperationalError as e:
            code = e.args[0]
            if attempts == 2 or code != 1213:
                raise e
            attempts += 1
            time.sleep(0.2)

django.db.backends.utils.CursorWrapper.execute = execute_wrapper

What the code above does is: it will try running the query and if an OperationalError is thrown with the error code 1213 (a deadlock), it will wait for 200 ms and try again. It will do this 3 times and if after 3 times the problem was not solved, the original exception is raised.

This code should be executed when the django project is being loaded into memory and so a good place to put it is in the __init__.py file of any of your apps (I placed in the __init__.py file of my project's main directory - the one that has the same name as your django project).

Hope this helps anyone in the future.

like image 166
Luccas Correa Avatar answered Sep 20 '22 03:09

Luccas Correa