Skip to content

Commit 697e1fb

Browse files
committed
MSC4140: don't cancel delayed state on own state
When a user sends a state event, do not cancel their own delayed events for the same piece of state.
1 parent 05576f0 commit 697e1fb

3 files changed

Lines changed: 128 additions & 31 deletions

File tree

synapse/handlers/delayed_events.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,18 +181,36 @@ async def _unsafe_process_new_event(self) -> None:
181181

182182
async def _handle_state_deltas(self, deltas: List[StateDelta]) -> None:
183183
"""
184-
Process current state deltas to cancel pending delayed events
184+
Process current state deltas to cancel other users' pending delayed events
185185
that target the same state.
186186
"""
187187
for delta in deltas:
188+
if delta.event_id is None:
189+
logger.debug(
190+
"Not handling delta for deleted state: %r %r",
191+
delta.event_type,
192+
delta.state_key,
193+
)
194+
continue
195+
188196
logger.debug(
189197
"Handling: %r %r, %s", delta.event_type, delta.state_key, delta.event_id
190198
)
191199

200+
event = await self._store.get_event(
201+
delta.event_id, check_room_id=delta.room_id
202+
)
203+
sender = UserID.from_string(event.sender)
204+
192205
next_send_ts = await self._store.cancel_delayed_state_events(
193206
room_id=delta.room_id,
194207
event_type=delta.event_type,
195208
state_key=delta.state_key,
209+
not_from_localpart=(
210+
sender.localpart
211+
if sender.domain == self._config.server.server_name
212+
else ""
213+
),
196214
)
197215

198216
if self._next_send_ts_changed(next_send_ts):

synapse/storage/databases/main/delayed_events.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ 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.
@@ -434,15 +435,19 @@ async def cancel_delayed_state_events(
434435
def cancel_delayed_state_events_txn(
435436
txn: LoggingTransaction,
436437
) -> 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-
},
438+
txn.execute(
439+
"""
440+
DELETE FROM delayed_events
441+
WHERE room_id = ? AND event_type = ? AND state_key = ?
442+
AND user_localpart <> ?
443+
AND NOT is_processed
444+
""",
445+
(
446+
room_id,
447+
event_type,
448+
state_key,
449+
not_from_localpart,
450+
),
446451
)
447452
return self._get_next_delayed_event_send_ts_txn(txn)
448453

0 commit comments

Comments
 (0)