Skip to content

Commit d2d48cc

Browse files
Refactor Sync handler to be able to return different sync responses (SyncVersion) (#17200)
Refactor Sync handler to be able to be able to return different sync responses (`SyncVersion`). Preparation to be able support sync v2 and a new Sliding Sync `/sync/e2ee` endpoint which returns a subset of sync v2. Split upon request: #17167 (comment) Split from #17167 where we will add `SyncVersion.E2EE_SYNC` and a new type of sync response.
1 parent 2359c64 commit d2d48cc

File tree

5 files changed

+128
-25
lines changed

5 files changed

+128
-25
lines changed

changelog.d/17200.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Prepare sync handler to be able to return different sync responses (`SyncVersion`).

synapse/handlers/sync.py

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#
2121
import itertools
2222
import logging
23+
from enum import Enum
2324
from typing import (
2425
TYPE_CHECKING,
2526
AbstractSet,
@@ -112,6 +113,23 @@
112113
SyncRequestKey = Tuple[Any, ...]
113114

114115

116+
class SyncVersion(Enum):
117+
"""
118+
Enum for specifying the version of sync request. This is used to key which type of
119+
sync response that we are generating.
120+
121+
This is different than the `sync_type` you might see used in other code below; which
122+
specifies the sub-type sync request (e.g. initial_sync, full_state_sync,
123+
incremental_sync) and is really only relevant for the `/sync` v2 endpoint.
124+
"""
125+
126+
# These string values are semantically significant because they are used in the the
127+
# metrics
128+
129+
# Traditional `/sync` endpoint
130+
SYNC_V2 = "sync_v2"
131+
132+
115133
@attr.s(slots=True, frozen=True, auto_attribs=True)
116134
class SyncConfig:
117135
user: UserID
@@ -309,13 +327,25 @@ async def wait_for_sync_for_user(
309327
self,
310328
requester: Requester,
311329
sync_config: SyncConfig,
330+
sync_version: SyncVersion,
312331
since_token: Optional[StreamToken] = None,
313332
timeout: int = 0,
314333
full_state: bool = False,
315334
) -> SyncResult:
316335
"""Get the sync for a client if we have new data for it now. Otherwise
317336
wait for new data to arrive on the server. If the timeout expires, then
318337
return an empty sync result.
338+
339+
Args:
340+
requester: The user requesting the sync response.
341+
sync_config: Config/info necessary to process the sync request.
342+
sync_version: Determines what kind of sync response to generate.
343+
since_token: The point in the stream to sync from.
344+
timeout: How long to wait for new data to arrive before giving up.
345+
full_state: Whether to return the full state for each room.
346+
347+
Returns:
348+
When `SyncVersion.SYNC_V2`, returns a full `SyncResult`.
319349
"""
320350
# If the user is not part of the mau group, then check that limits have
321351
# not been exceeded (if not part of the group by this point, almost certain
@@ -327,6 +357,7 @@ async def wait_for_sync_for_user(
327357
sync_config.request_key,
328358
self._wait_for_sync_for_user,
329359
sync_config,
360+
sync_version,
330361
since_token,
331362
timeout,
332363
full_state,
@@ -338,6 +369,7 @@ async def wait_for_sync_for_user(
338369
async def _wait_for_sync_for_user(
339370
self,
340371
sync_config: SyncConfig,
372+
sync_version: SyncVersion,
341373
since_token: Optional[StreamToken],
342374
timeout: int,
343375
full_state: bool,
@@ -363,9 +395,11 @@ async def _wait_for_sync_for_user(
363395
else:
364396
sync_type = "incremental_sync"
365397

398+
sync_label = f"{sync_version}:{sync_type}"
399+
366400
context = current_context()
367401
if context:
368-
context.tag = sync_type
402+
context.tag = sync_label
369403

370404
# if we have a since token, delete any to-device messages before that token
371405
# (since we now know that the device has received them)
@@ -384,14 +418,16 @@ async def _wait_for_sync_for_user(
384418
# we are going to return immediately, so don't bother calling
385419
# notifier.wait_for_events.
386420
result: SyncResult = await self.current_sync_for_user(
387-
sync_config, since_token, full_state=full_state
421+
sync_config, sync_version, since_token, full_state=full_state
388422
)
389423
else:
390424
# Otherwise, we wait for something to happen and report it to the user.
391425
async def current_sync_callback(
392426
before_token: StreamToken, after_token: StreamToken
393427
) -> SyncResult:
394-
return await self.current_sync_for_user(sync_config, since_token)
428+
return await self.current_sync_for_user(
429+
sync_config, sync_version, since_token
430+
)
395431

396432
result = await self.notifier.wait_for_events(
397433
sync_config.user.to_string(),
@@ -416,13 +452,14 @@ async def current_sync_callback(
416452
lazy_loaded = "true"
417453
else:
418454
lazy_loaded = "false"
419-
non_empty_sync_counter.labels(sync_type, lazy_loaded).inc()
455+
non_empty_sync_counter.labels(sync_label, lazy_loaded).inc()
420456

421457
return result
422458

423459
async def current_sync_for_user(
424460
self,
425461
sync_config: SyncConfig,
462+
sync_version: SyncVersion,
426463
since_token: Optional[StreamToken] = None,
427464
full_state: bool = False,
428465
) -> SyncResult:
@@ -431,12 +468,26 @@ async def current_sync_for_user(
431468
This is a wrapper around `generate_sync_result` which starts an open tracing
432469
span to track the sync. See `generate_sync_result` for the next part of your
433470
indoctrination.
471+
472+
Args:
473+
sync_config: Config/info necessary to process the sync request.
474+
sync_version: Determines what kind of sync response to generate.
475+
since_token: The point in the stream to sync from.p.
476+
full_state: Whether to return the full state for each room.
477+
Returns:
478+
When `SyncVersion.SYNC_V2`, returns a full `SyncResult`.
434479
"""
435480
with start_active_span("sync.current_sync_for_user"):
436481
log_kv({"since_token": since_token})
437-
sync_result = await self.generate_sync_result(
438-
sync_config, since_token, full_state
439-
)
482+
# Go through the `/sync` v2 path
483+
if sync_version == SyncVersion.SYNC_V2:
484+
sync_result: SyncResult = await self.generate_sync_result(
485+
sync_config, since_token, full_state
486+
)
487+
else:
488+
raise Exception(
489+
f"Unknown sync_version (this is a Synapse problem): {sync_version}"
490+
)
440491

441492
set_tag(SynapseTags.SYNC_RESULT, bool(sync_result))
442493
return sync_result

synapse/rest/client/sync.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
KnockedSyncResult,
4141
SyncConfig,
4242
SyncResult,
43+
SyncVersion,
4344
)
4445
from synapse.http.server import HttpServer
4546
from synapse.http.servlet import RestServlet, parse_boolean, parse_integer, parse_string
@@ -232,6 +233,7 @@ async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
232233
sync_result = await self.sync_handler.wait_for_sync_for_user(
233234
requester,
234235
sync_config,
236+
SyncVersion.SYNC_V2,
235237
since_token=since_token,
236238
timeout=timeout,
237239
full_state=full_state,

tests/events/test_presence_router.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
from synapse.types import JsonDict, StreamToken, create_requester
3737
from synapse.util import Clock
3838

39-
from tests.handlers.test_sync import generate_sync_config
39+
from tests.handlers.test_sync import SyncVersion, generate_sync_config
4040
from tests.unittest import (
4141
FederatingHomeserverTestCase,
4242
HomeserverTestCase,
@@ -521,7 +521,7 @@ def sync_presence(
521521
sync_config = generate_sync_config(requester.user.to_string())
522522
sync_result = testcase.get_success(
523523
testcase.hs.get_sync_handler().wait_for_sync_for_user(
524-
requester, sync_config, since_token
524+
requester, sync_config, SyncVersion.SYNC_V2, since_token
525525
)
526526
)
527527

0 commit comments

Comments
 (0)