Interview question
Handle an optimistic version conflict with SQLAlchemy
Uses SQLAlchemy version counters and an HTTP precondition to reject stale writes without silently overwriting newer state.
TL;DR
Uses SQLAlchemy version counters and an HTTP precondition to reject stale writes without silently overwriting newer state.
version_id_col, StaleDataError, request preconditions, transaction rollback, response versions, and conflict semantics.
Practice the problem like a real interview: restate, reason, implement, and test.
An order update receives the version last seen by the client. Configure SQLAlchemy optimistic versioning so a concurrent update changes the version and a stale update fails. Translate the stale write into the API's documented 409 or 412 response and never retry a user edit silently.
Move to the linked follow-up, next path step, prerequisite, or deeper variant.
Practice the next layer of the same subject.
client A reads version 4
client B commits version 5
client A updates expected version 4 -> precondition failure
version_id as SQLAlchemy's version column.version_id_col on the mapped order.StaleDataError outside the failed transaction and translate it.from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.orm.exc import StaleDataError
class Order(Base):
__tablename__ = "orders"
id: Mapped[int] = mapped_column(primary_key=True)
status: Mapped[str]
version_id: Mapped[int] = mapped_column(nullable=False, default=1)
__mapper_args__ = {"version_id_col": version_id}
async def change_status(session_factory, order_id: int, expected: int, status: str):
try:
async with session_factory() as session:
async with session.begin():
order = await session.get(Order, order_id)
if order is None:
raise OrderNotFound(order_id)
if order.version_id != expected:
raise StaleOrder(expected)
order.status = status
await session.flush()
new_version = order.version_id
return new_version
except StaleDataError as exc:
# The transaction context has rolled back before translation.
raise StaleOrder(expected) from exc
The indexed lookup and conditional update are O(log n). A conflict costs a rollback and client-visible resolution path.
Spot a weak answer, missing edge case, or clearer explanation? Send it in.
Say thanks with a standalone, one-time $5 contribution. No account required.