Skip to content

Commit 51df675

Browse files
authored
MSC4140: don't cancel delayed state on own state (#17810)
When a user sends a state event, do not cancel their own delayed events for the same piece of state. For context, see [the relevant section in the MSC](https://github.com/matrix-org/matrix-spec-proposals/blob/a09a883d9a013ac4b6ffddebd7ea87a827d211b9/proposals/4140-delayed-events-futures.md#delayed-state-events-are-cancelled-by-a-more-recent-state-event).
1 parent 59a15da commit 51df675

File tree

4 files changed

+158
-36
lines changed

4 files changed

+158
-36
lines changed

changelog.d/17810.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Update MSC4140 implementation to no longer cancel a user's own delayed state events with an event type & state key that match a more recent state event sent by that user.

synapse/handlers/delayed_events.py

+19-1
Original file line numberDiff line numberDiff line change
@@ -191,18 +191,36 @@ async def _unsafe_process_new_event(self) -> None:
191191

192192
async def _handle_state_deltas(self, deltas: List[StateDelta]) -> None:
193193
"""
194-
Process current state deltas to cancel pending delayed events
194+
Process current state deltas to cancel other users' pending delayed events
195195
that target the same state.
196196
"""
197197
for delta in deltas:
198+
if delta.event_id is None:
199+
logger.debug(
200+
"Not handling delta for deleted state: %r %r",
201+
delta.event_type,
202+
delta.state_key,
203+
)
204+
continue
205+
198206
logger.debug(
199207
"Handling: %r %r, %s", delta.event_type, delta.state_key, delta.event_id
200208
)
201209

210+
event = await self._store.get_event(
211+
delta.event_id, check_room_id=delta.room_id
212+
)
213+
sender = UserID.from_string(event.sender)
214+
202215
next_send_ts = await self._store.cancel_delayed_state_events(
203216
room_id=delta.room_id,
204217
event_type=delta.event_type,
205218
state_key=delta.state_key,
219+
not_from_localpart=(
220+
sender.localpart
221+
if sender.domain == self._config.server.server_name
222+
else ""
223+
),
206224
)
207225

208226
if self._next_send_ts_changed(next_send_ts):

synapse/storage/databases/main/delayed_events.py

+21-9
Original file line numberDiff line numberDiff line change
@@ -424,25 +424,37 @@ async def cancel_delayed_state_events(
424424
room_id: str,
425425
event_type: str,
426426
state_key: str,
427+
not_from_localpart: str,
427428
) -> Optional[Timestamp]:
428429
"""
429430
Cancels all matching delayed state events, i.e. remove them as long as they haven't been processed.
430431
432+
Args:
433+
room_id: The room ID to match against.
434+
event_type: The event type to match against.
435+
state_key: The state key to match against.
436+
not_from_localpart: The localpart of a user whose delayed events to not cancel.
437+
If set to the empty string, any users' delayed events may be cancelled.
438+
431439
Returns: The send time of the next delayed event to be sent, if any.
432440
"""
433441

434442
def cancel_delayed_state_events_txn(
435443
txn: LoggingTransaction,
436444
) -> Optional[Timestamp]:
437-
self.db_pool.simple_delete_txn(
438-
txn,
439-
table="delayed_events",
440-
keyvalues={
441-
"room_id": room_id,
442-
"event_type": event_type,
443-
"state_key": state_key,
444-
"is_processed": False,
445-
},
445+
txn.execute(
446+
"""
447+
DELETE FROM delayed_events
448+
WHERE room_id = ? AND event_type = ? AND state_key = ?
449+
AND user_localpart <> ?
450+
AND NOT is_processed
451+
""",
452+
(
453+
room_id,
454+
event_type,
455+
state_key,
456+
not_from_localpart,
457+
),
446458
)
447459
return self._get_next_delayed_event_send_ts_txn(txn)
448460

0 commit comments

Comments
 (0)