mirror of
https://github.com/zulip/zulip.git
synced 2025-11-05 06:23:38 +00:00
access_message: Allow selecting message row FOR UPDATE.
This is a prep change to start using `SELECT FOR UPDATE` queries when there is a chance of race conditions.
This commit is contained in:
committed by
Tim Abbott
parent
51f5bbcd57
commit
1a9f385e17
@@ -655,7 +655,9 @@ class ReactionDict:
|
|||||||
|
|
||||||
|
|
||||||
def access_message(
|
def access_message(
|
||||||
user_profile: UserProfile, message_id: int
|
user_profile: UserProfile,
|
||||||
|
message_id: int,
|
||||||
|
lock_message: bool = False,
|
||||||
) -> Tuple[Message, Optional[UserMessage]]:
|
) -> Tuple[Message, Optional[UserMessage]]:
|
||||||
"""You can access a message by ID in our APIs that either:
|
"""You can access a message by ID in our APIs that either:
|
||||||
(1) You received or have previously accessed via starring
|
(1) You received or have previously accessed via starring
|
||||||
@@ -664,9 +666,21 @@ def access_message(
|
|||||||
|
|
||||||
We produce consistent, boring error messages to avoid leaking any
|
We produce consistent, boring error messages to avoid leaking any
|
||||||
information from a security perspective.
|
information from a security perspective.
|
||||||
|
|
||||||
|
The lock_message parameter should be passed by callers that are
|
||||||
|
planning to modify the Message object. This will use the SQL
|
||||||
|
`SELECT FOR UPDATE` feature to ensure that other processes cannot
|
||||||
|
delete the message during the current transaction, which is
|
||||||
|
important to prevent rare race conditions. Callers must only
|
||||||
|
pass lock_message when inside a @transaction.atomic block.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
message = Message.objects.select_related().get(id=message_id)
|
base_query = Message.objects.select_related()
|
||||||
|
if lock_message: # nocoverage
|
||||||
|
# We want to lock only the `Message` row, and not the related fields
|
||||||
|
# because the `Message` row only has a possibility of races.
|
||||||
|
base_query = base_query.select_for_update(of=("self",))
|
||||||
|
message = base_query.get(id=message_id)
|
||||||
except Message.DoesNotExist:
|
except Message.DoesNotExist:
|
||||||
raise JsonableError(_("Invalid message(s)"))
|
raise JsonableError(_("Invalid message(s)"))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user