From 8181e290a90bc7b7f950fb639b38d0212dca87da Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Fri, 21 Jun 2019 11:10:27 +0100 Subject: [PATCH 1/3] Fix sync tightloop bug. If, for some reason, presence updates take a while to persist then it can trigger clients to tightloop calling `/sync` due to the presence handler returning updates but not advancing the stream token. Fixes #5503. --- synapse/handlers/presence.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/synapse/handlers/presence.py b/synapse/handlers/presence.py index 5204073a3..3edd35998 100644 --- a/synapse/handlers/presence.py +++ b/synapse/handlers/presence.py @@ -1017,11 +1017,21 @@ class PresenceEventSource(object): if from_key is not None: from_key = int(from_key) + max_token = self.store.get_current_presence_token() + if from_key == max_token: + # This is necessary as due to the way stream ID generators work + # we may get updates that have a stream ID greater than the max + # token. This is usually fine, as it just means that we may send + # down some presence updates multiple times. However, we need to + # be careful that the sync stream actually does make some + # progress, otherwise clients will end up tight looping calling + # /sync due to it returning the same token repeatedly. Hence + # this guard. C.f. #5503. + defer.returnValue(([], max_token)) + presence = self.get_presence_handler() stream_change_cache = self.store.presence_stream_cache - max_token = self.store.get_current_presence_token() - users_interested_in = yield self._get_interested_in(user, explicit_room_id) user_ids_changed = set() From 8d452e0ca574ba466a6cf7eb78ca6fdb8acebb7e Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Fri, 21 Jun 2019 11:13:13 +0100 Subject: [PATCH 2/3] Newsfile --- changelog.d/5507.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/5507.bugfix diff --git a/changelog.d/5507.bugfix b/changelog.d/5507.bugfix new file mode 100644 index 000000000..70452aa14 --- /dev/null +++ b/changelog.d/5507.bugfix @@ -0,0 +1 @@ +Fix bug where clients could tight loop calling `/sync` for a period. From 915280f1edec3ddfe6261940d91ef451f207ed15 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Mon, 1 Jul 2019 10:22:42 +0100 Subject: [PATCH 3/3] Fixup comment --- synapse/handlers/presence.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/synapse/handlers/presence.py b/synapse/handlers/presence.py index 3edd35998..c80dc2eba 100644 --- a/synapse/handlers/presence.py +++ b/synapse/handlers/presence.py @@ -1021,12 +1021,19 @@ class PresenceEventSource(object): if from_key == max_token: # This is necessary as due to the way stream ID generators work # we may get updates that have a stream ID greater than the max - # token. This is usually fine, as it just means that we may send - # down some presence updates multiple times. However, we need to - # be careful that the sync stream actually does make some - # progress, otherwise clients will end up tight looping calling - # /sync due to it returning the same token repeatedly. Hence - # this guard. C.f. #5503. + # token (e.g. max_token is N but stream generator may return + # results for N+2, due to N+1 not having finished being + # persisted yet). + # + # This is usually fine, as it just means that we may send down + # some presence updates multiple times. However, we need to be + # careful that the sync stream either actually does make some + # progress or doesn't return, otherwise clients will end up + # tight looping calling /sync due to it immediately returning + # the same token repeatedly. + # + # Hence this guard where we just return nothing so that the sync + # doesn't return. C.f. #5503. defer.returnValue(([], max_token)) presence = self.get_presence_handler()