Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/19613.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Reorder rooms by read receipts to update most important rooms first.
Comment thread
MadLittleMods marked this conversation as resolved.
Comment thread
MadLittleMods marked this conversation as resolved.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing from the review queue until #19613 (comment) gets some attention ⏩

34 changes: 28 additions & 6 deletions synapse/handlers/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@
#
import logging
import random
from bisect import bisect_right
from typing import TYPE_CHECKING

from twisted.internet.defer import CancelledError

from synapse.api.constants import ProfileFields
from synapse.api.constants import ProfileFields, ReceiptTypes
from synapse.api.errors import (
AuthError,
Codes,
Expand Down Expand Up @@ -671,6 +670,27 @@ async def _update_join_states(

target_user_str = target_user.to_string()

# Compute the ordered list of rooms upfront to ensure consistency across restarts
all_room_ids = await self.store.get_rooms_for_user(target_user_str)

# Get the user's latest read receipts for all rooms
user_receipts = await self.store.get_receipts_for_user_with_orderings(
target_user_str,
[ReceiptTypes.READ, ReceiptTypes.READ_PRIVATE],
)

# Sort rooms by most recent read receipt (highest stream_ordering first),
# with fallback to alphabetical ordering for rooms without receipts
def sort_key(room_id: str) -> tuple[int, str]:
if room_id in user_receipts:
# Rooms with receipts: sort by stream_ordering (descending) then by room_id
return (-user_receipts[room_id]["stream_ordering"], room_id)
else:
# Rooms without receipts: sort alphabetically after all rooms with receipts
return (0, room_id)

room_ids = sorted(all_room_ids, key=sort_key)

# Cancel any ongoing profile membership updates for this user,
# and start a new one.
async with self._worker_locks.acquire_lock(
Expand All @@ -691,6 +711,7 @@ async def _update_join_states(
resource_id=target_user_str,
params={
"requester_authenticated_entity": requester.authenticated_entity,
"ordered_room_ids": room_ids,
},
)

Expand All @@ -702,15 +723,16 @@ async def _update_join_states_task(
assert task.params

target_user = UserID.from_string(task.resource_id)
room_ids = sorted(await self.store.get_rooms_for_user(target_user.to_string()))

# Use the precomputed room ordering from task params to ensure consistency
room_ids = task.params.get("ordered_room_ids", [])

last_room_id = task.result.get("last_room_id", None) if task.result else None

if last_room_id:
# Filter out room IDs that have already been handled
# by finding the first room ID greater than the last handled room ID
# and slicing the list from that point onwards.
room_ids = room_ids[bisect_right(room_ids, last_room_id) :]
last_index = room_ids.index(last_room_id, 0)
room_ids = room_ids[last_index + 1 :]

requester = create_requester(
user_id=target_user,
Expand Down
Loading
Loading