This repository has been archived by the owner on Apr 26, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Recheck if remote device is cached before requesting it #16252
Merged
Merged
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
0469b0b
Recheck if remote device is cached before requesting it
erikjohnston 94ca43f
Newsfile
erikjohnston e05ccb5
Linearize requests to fetch remote devices
erikjohnston 0676302
Merge remote-tracking branch 'origin/develop' into erikj/recheck_if_d…
erikjohnston File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Fix bug when using workers where Synapse could end up re-requesting the same remote device repeatedly. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,6 +43,7 @@ | |
) | ||
from synapse.types import ( | ||
JsonDict, | ||
JsonMapping, | ||
StrCollection, | ||
StreamKeyType, | ||
StreamToken, | ||
|
@@ -982,7 +983,7 @@ def __init__(self, hs: "HomeServer"): | |
|
||
async def multi_user_device_resync( | ||
self, user_ids: List[str], mark_failed_as_stale: bool = True | ||
) -> Dict[str, Optional[JsonDict]]: | ||
) -> Dict[str, Optional[JsonMapping]]: | ||
""" | ||
Like `user_device_resync` but operates on multiple users **from the same origin** | ||
at once. | ||
|
@@ -1011,6 +1012,7 @@ def __init__(self, hs: "HomeServer", device_handler: DeviceHandler): | |
self._notifier = hs.get_notifier() | ||
|
||
self._remote_edu_linearizer = Linearizer(name="remote_device_list") | ||
self._resync_linearizer = Linearizer(name="remote_device_resync") | ||
|
||
# user_id -> list of updates waiting to be handled. | ||
self._pending_updates: Dict[ | ||
|
@@ -1253,7 +1255,7 @@ async def _maybe_retry_device_resync(self) -> None: | |
|
||
async def multi_user_device_resync( | ||
self, user_ids: List[str], mark_failed_as_stale: bool = True | ||
) -> Dict[str, Optional[JsonDict]]: | ||
) -> Dict[str, Optional[JsonMapping]]: | ||
""" | ||
Like `user_device_resync` but operates on multiple users **from the same origin** | ||
at once. | ||
|
@@ -1273,9 +1275,11 @@ async def multi_user_device_resync( | |
failed = set() | ||
# TODO(Perf): Actually batch these up | ||
for user_id in user_ids: | ||
user_result, user_failed = await self._user_device_resync_returning_failed( | ||
user_id | ||
) | ||
async with self._resync_linearizer.queue(user_id): | ||
( | ||
user_result, | ||
user_failed, | ||
) = await self._user_device_resync_returning_failed(user_id) | ||
result[user_id] = user_result | ||
if user_failed: | ||
failed.add(user_id) | ||
|
@@ -1287,7 +1291,7 @@ async def multi_user_device_resync( | |
|
||
async def _user_device_resync_returning_failed( | ||
self, user_id: str | ||
) -> Tuple[Optional[JsonDict], bool]: | ||
) -> Tuple[Optional[JsonMapping], bool]: | ||
"""Fetches all devices for a user and updates the device cache with them. | ||
|
||
Args: | ||
|
@@ -1300,6 +1304,12 @@ async def _user_device_resync_returning_failed( | |
e.g. due to a connection problem. | ||
- True iff the resync failed and the device list should be marked as stale. | ||
""" | ||
# Check that we haven't gone and fetched the devices since we last | ||
# checked if we needed to resync these device lists. | ||
if await self.store.get_users_whose_devices_are_cached([user_id]): | ||
cached = await self.store.get_cached_devices_for_user(user_id) | ||
return cached, False | ||
Comment on lines
+1354
to
+1358
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is safe because if we linearized on user ID, then request the same user again but have not received a request to invalidate that data (via a resync request) then it must still be valid? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, we already do do this check before entering this block, so this is safe. The flow is:
So this is step 5, which is safe because we're basically re-doing a check we have previously done |
||
|
||
logger.debug("Attempting to resync the device list for %s", user_id) | ||
log_kv({"message": "Doing resync to update device list."}) | ||
# Fetch all devices for the user. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is queueing the right thing here? Should we instead share the results via an
ObservableDeferred
? (If you have two requests for the same user in a row there's no reason to service the second if the first is ongoing?)Edit: It looks like this is essentially what we're doing by checking the cache inside of
_user_device_resync_returning_failed
?Will this make it harder to batch these? (Maybe not the immediate concern, but don't want to design ourselves into a corner.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If these weren't device lists I would be more gung ho about batching these up. However, we need to make sure that we don't break any semantics. Specifically I'm worried about the situations where we get two requests for a remote users device lists, one that happens before we get poked about a new device and one after, if we coalesce those two remote calls we need to make sure that we don't return the old set of devices (retrieved by the first request) to the second request. IYSWIM....
I don't think this backs us in to a corner, we can always change this down the line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we're not talking about the same batching -- I was talking about batching multiple users (based on the comment a few lines above this), but maybe that's tricky.