Expose MSC4354 Sticky Events over MSC4186 (Simplified) Sliding Sync.#19591
Expose MSC4354 Sticky Events over MSC4186 (Simplified) Sliding Sync.#19591reivilibre wants to merge 14 commits intodevelopfrom
Conversation
| If you want a Pydantic-compatible Sentinel that is suitable for expressing | ||
| 'absent from some parsed JSON payload' or equivalent, see `Absent`. |
There was a problem hiding this comment.
Being honest, I discovered Sentinel.UNSET_SENTINEL after having written Absent, so this is post-hoc justification, however I also think it's valuable to have a clean domain-specific 'absent' marker that is not also repurposed for other uses throughout the code. The name Absent also seems clearer to me than Sentinel if I was reading a Pydantic schema, but it's also fair to say that a quick go-to-definition would clear that up.
Open to opinions though; it could be the case that it makes sense to unify them after all.
There was a problem hiding this comment.
Probably makes sense to unify all of them as all of the use cases are absent use cases.
I'm not really understanding the distinction between "non-API-facing" either.
360c60b to
adb3191
Compare
97efd43 to
6883dcd
Compare
Fixes builtins.NotImplementedError: Cannot check isinstance when validating from json, use a JsonOrPython validator instead.
This reverts commit 6883dcd. EPEL 10 only had 2.9.2 so try to work around issue without updating
builtins.NotImplementedError: Cannot check isinstance when validating from json, use a JsonOrPython validator instead.
6883dcd to
c5c1b01
Compare
| For a Sentinel for internal (non-API-facing) use, instead consider | ||
| `Sentinel.UNSET_SENTINEL`. |
There was a problem hiding this comment.
Wording seems off
| For a Sentinel for internal (non-API-facing) use, instead consider | |
| `Sentinel.UNSET_SENTINEL`. | |
| For internal (non-API-facing) use, consider `Sentinel.UNSET_SENTINEL`. |
(also applies to the Absent docstring below)
| # Making this an Enum member makes this compatible with type narrowing, | ||
| # meaning `x is not Absent` will narrow `x: int | AbsentType` to `x: int` etc. | ||
| _Absent = object() |
There was a problem hiding this comment.
We should align the comments between this and Sentinel.UNSET_SENTINEL
| @classmethod | ||
| def __get_pydantic_core_schema__( | ||
| cls, source_type: object, handler: GetCoreSchemaHandler | ||
| ) -> CoreSchema: |
There was a problem hiding this comment.
We should comment why we define this
| NonNegativeStrictInt = Annotated[StrictInt, annotated_types.Ge(0)] | ||
| """A strict integer that must be greater than or equal to zero. | ||
|
|
||
| Should be preferred in place of Pydantic's own (lax) NonNegativeInt. |
| If you want a Pydantic-compatible Sentinel that is suitable for expressing | ||
| 'absent from some parsed JSON payload' or equivalent, see `Absent`. |
There was a problem hiding this comment.
Probably makes sense to unify all of them as all of the use cases are absent use cases.
I'm not really understanding the distinction between "non-API-facing" either.
| since_token = sticky_events_request.since or SlidingSyncStickyEventsToken( | ||
| sticky_events_stream_id=0 | ||
| ) | ||
| ( | ||
| sticky_events_to_id, | ||
| room_to_event_ids, | ||
| ) = await self.store.get_sticky_events_in_rooms( | ||
| all_interested_room_ids, | ||
| from_id=since_token.sticky_events_stream_id, | ||
| to_id=to_token.sticky_events_key, | ||
| now=now, | ||
| limit=min(sticky_events_request.limit, StickyEvent.MAX_EVENTS_IN_SYNC), | ||
| ) |
There was a problem hiding this comment.
The Sticky Events extension having it's own pagination inside Sliding Sync seems like a smell to me.
Related discussion: matrix-org/matrix-spec-proposals#4354 (comment)
| PATTERN = re.compile(r"^sticky_([0-9]+)$") | ||
|
|
||
| def __init__(self, *, sticky_events_stream_id: int) -> None: | ||
| self.sticky_events_stream_id = sticky_events_stream_id |
There was a problem hiding this comment.
Re: #19365 (comment)
Seems like we should be using MultiWriterStreamToken or we should at-least FIXME with our desire
| @classmethod | ||
| def __get_pydantic_core_schema__( | ||
| cls, source_type: object, handler: GetCoreSchemaHandler | ||
| ) -> CoreSchema: |
There was a problem hiding this comment.
Comment to explain why we have these methods
| response_body, _ = self.do_sync(sync_body, tok=user1_tok) | ||
| self._assert_sticky_events_response(response_body, None) | ||
|
|
||
| def test_wait_for_new_data(self) -> None: |
There was a problem hiding this comment.
I would expect to also see test_wait_for_new_data_timeout (like other extensions)
| """ | ||
|
|
||
|
|
||
| class SlidingSyncStickyEventsExtensionTestCase(SlidingSyncBase): |
There was a problem hiding this comment.
I didn't analyze the tests that closely yet. Skimming-wise the coverage seemed pretty good
Follows: #19487
Part of: MSC4354 whose experimental feature tracking issue is #19409
This PR implements the Sliding Sync (MSC4186) extension described in MSC4354, allowing sliding sync clients
to receive sticky events in a reliable way.
The logic is much the same as for oldschool sync (implementation in #19487),
although in the sliding sync extension, the client can choose their own limit
and must control their own pagination through an extra token in the extension request/response bodies.
EDIT: Note this PR does not yet send down existing sticky events in the room when the room has been newly-joined.
This newly-discovered gap is tracked at #19662 and will be addressed for both current sync and MSC4186 SSS soon.
This pull request is commit-by-commit review friendly.
Add gather_optional_coroutines/7 overload
Add fields for sticky events sliding sync extension
Add explicit Absent utility type
Implement sliding sync extension for sticky events
Add sliding sync extension test
drive-by docstring tweak on ordering