From c6ae3e72429bc6c19a4f2d4ec0d7cde3169c86be Mon Sep 17 00:00:00 2001 From: Alex Vandiver Date: Tue, 21 Nov 2023 16:55:46 +0000 Subject: [PATCH] zilencer: Lock the RemoteZulipServer row when inserting data. This does not ensure that we do not mix data from multiple servers sharing a UUID -- if one has more `RemoteRealmCount` rows, and the other has more `RemoteInstalltionCount` rows, the end result will still be some rows from each server, across the two tables. It does ensure that we will not alternate rows between two servers if both requests are processed at the same time. It also causes submissions to be all-or-nothing in the event of integrity errors. This is not necessarily beneficial, as forward progress is generally useful -- but the integrity errors are resolved in the subsequent commit. --- zilencer/views.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zilencer/views.py b/zilencer/views.py index c2035f0162..0b7f5be0a9 100644 --- a/zilencer/views.py +++ b/zilencer/views.py @@ -617,6 +617,7 @@ class InstallationCountDataForAnalytics(BaseModel): @typed_endpoint +@transaction.atomic def remote_server_post_analytics( request: HttpRequest, server: RemoteZulipServer, @@ -627,6 +628,10 @@ def remote_server_post_analytics( realms: Optional[Json[List[RealmDataForAnalytics]]] = None, version: Optional[Json[str]] = None, ) -> HttpResponse: + # Lock the server, preventing this from racing with other + # duplicate submissions of the data + server = RemoteZulipServer.objects.select_for_update().get(id=server.id) + if version is not None: version = version[0 : RemoteZulipServer.VERSION_MAX_LENGTH] if version != server.last_version: