Retry on deadlock for MySQL / SQLAlchemy

database-deadlocks, mysql, python, sqlalchemy

Solution

You can't really do that with the `Session` from the outside. `Session` would have to support this internally. It would involve saving a lot of private state, so this may not be worth your time.

I completely ditched most ORM stuff in favour of the lower level SQLAlchemy Core interface. Using that (or even any dbapi interface) you can trivially use your `retry_on_deadlock_decorator` decorator (see question above) to make a retry-aware `db.execute` wrapper.

 @retry_on_deadlock_decorator
 def deadlock_safe_execute(db, stmt, *args, **kw):
     return db.execute(stmt, *args, **kw)

And instead of

 db.execute("UPDATE users SET active=0")

you do

 deadlock_safe_execute(db, "UPDATE users SET active=0")

which will retry automatically if a deadlock happens.

Problem

I have searched for quite some time now and can't found a solution to my problem. We are using SQLAlchemy in conjunction with MySQL for our project and we encounter several time the dreaded error: 1213, 'Deadlock found when trying to get lock; try restarting transaction'. We would like to try to restart the transaction at most three times in this case. I have started to write a decorator that does this but i don't know how to save the session state before the fail and retry the same transaction after it ? (As SQLAlchemy requires a rollback whenever an exception is raised) My work so far, ``` def retry_on_deadlock_decorator(func): lock_messages_error = ['Deadlock found', 'Lock wait timeout exceeded'] @wraps(func) def wrapper(*args, **kwargs): attempt_count = 0 while attempt_count < settings.MAXIMUM_RETRY_ON_DEADLOCK: try: return func(*args, **kwargs) except OperationalError as e: if any(msg in e.message for msg in lock_messages_error) \ and attempt_count <= settings.MAXIMUM_RETRY_ON_DEADLOCK: logger.error('Deadlock detected. Trying sql transaction once more. Attempts count: %s' % (attempt_count + 1)) else: raise attempt_count += 1 return wrapper ```

Original source