Spot the bug
This retry loop still produces wrong results. Which line is the bug?
import psycopgfrom psycopg import IsolationLevelfrom psycopg.rows import TupleRowdef transfer(conn: psycopg.Connection[TupleRow], src: int, dst: int, amount: int) -> None:conn.isolation_level = IsolationLevel.SERIALIZABLErow = conn.execute("SELECT balance FROM accounts WHERE id = %s", (src,)).fetchone()assert row is not Nonefor attempt in range(5):try:if row[0] >= amount:conn.execute("UPDATE accounts SET balance = balance - %s"" WHERE id = %s",(amount, src),)conn.execute("UPDATE accounts SET balance = balance + %s"" WHERE id = %s",(amount, dst),)conn.commit()returnexcept psycopg.errors.SerializationFailure:conn.rollback()
Hint 1 of 1
What does a retry need to redo besides the writes?
Choose an answer, then open Show answer below to check it.
Show answer
- Answer: line 10
row = conn.execute(
The balance is read once, before the loop. Every retry reuses the stale value, so the decision isn't re-made on fresh data. The read must be inside the retried block. A second, smaller flaw: after 5 failures the loop falls through and returns None silently; re-raise on the last attempt.