python 33 lines · 6 steps

Retrying deadlocked DB writes in Flask

A parametrized decorator that transparently retries a view when the database reports a deadlock, backing off exponentially between attempts.

Explained by highlit
1import functools
2import time
3 
4from flask import current_app
5from sqlalchemy.exc import OperationalError
6 
7from app.extensions import db
8 
9_DEADLOCK_CODES = {1205, 1213, 40001}
10 
11 
12def retry_on_deadlock(max_retries=3, base_delay=0.05):
13 def decorator(view):
14 @functools.wraps(view)
15 def wrapper(*args, **kwargs):
16 attempt = 0
17 while True:
18 try:
19 return view(*args, **kwargs)
20 except OperationalError as exc:
21 db.session.rollback()
22 code = exc.orig.args[0] if exc.orig and exc.orig.args else None
23 if code not in _DEADLOCK_CODES or attempt >= max_retries:
24 raise
25 attempt += 1
26 delay = base_delay * (2 ** (attempt - 1))
27 current_app.logger.warning(
28 "Deadlock on %s (code=%s), retry %d/%d in %.3fs",
29 view.__name__, code, attempt, max_retries, delay,
30 )
31 time.sleep(delay)
32 return wrapper
33 return decorator
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Deadlocks are transient, so retrying the same transaction after a rollback often succeeds without any user-visible failure.
  2. 2A three-layer decorator lets you pass tuning parameters like retry count and delay while still wrapping the target cleanly.
  3. 3Exponential backoff spreads retries out over time, reducing the chance that competing transactions collide again immediately.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Retrying deadlocked DB writes in Flask — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code