Skip to content

Commit b056c8d

Browse files
committed
Improve method of incrementing display order and avoiding races.
1 parent 71efcbd commit b056c8d

File tree

1 file changed

+5
-9
lines changed

1 file changed

+5
-9
lines changed

api/src/shop/ordered_entity.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,17 @@ class OrderedEntity(Entity):
1313
can solve it with a trigger or like this using an explicit mysql lock.
1414
"""
1515

16-
def create(self, data=None, commit=True):
16+
def create(self, data: dict | None = None, commit: bool = True) -> dict:
1717
if data is None:
1818
data = request.json or {}
1919

20-
(status,) = db_session.execute(text("SELECT GET_LOCK('display_order', 20)")).fetchone()
21-
if not status:
22-
raise InternalServerError("Failed to create, try again later.", log="failed to aquire display_order lock")
20+
# Lock the rows for update to prevent race conditions
21+
max_display_order = db_session.query(func.max(self.model.display_order)).with_for_update().scalar()
22+
if data.get("display_order") is None:
23+
data["display_order"] = (max_display_order or 0) + 1
2324
try:
24-
if data.get("display_order") is None:
25-
data["display_order"] = (db_session.query(func.max(self.model.display_order)).scalar() or 0) + 1
2625
obj = self.to_obj(self._create_internal(data, commit=commit))
2726
return obj
2827
except Exception:
29-
# Rollback session if anything went wrong or we can't release the lock.
3028
db_session.rollback()
3129
raise
32-
finally:
33-
db_session.execute(text("DO RELEASE_LOCK('display_order')"))

0 commit comments

Comments
 (0)