From e9b53c8913e072989544c047b6076d163e1a5500 Mon Sep 17 00:00:00 2001 From: boatbomber Date: Fri, 14 Jul 2023 20:03:07 -0700 Subject: [PATCH 1/2] Switch main sync loop to non-recursive promise --- plugin/src/ServeSession.lua | 55 ++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/plugin/src/ServeSession.lua b/plugin/src/ServeSession.lua index 08dc40411..4e5116c81 100644 --- a/plugin/src/ServeSession.lua +++ b/plugin/src/ServeSession.lua @@ -299,27 +299,44 @@ function ServeSession:__initialSync(serverInfo) end function ServeSession:__mainSyncLoop() - return self.__apiContext:retrieveMessages() - :andThen(function(messages) - Log.trace("Serve session {} retrieved {} messages", tostring(self), #messages) - - for _, message in ipairs(messages) do - local unappliedPatch = self.__reconciler:applyPatch(message) - - if not PatchSet.isEmpty(unappliedPatch) then - Log.warn("Could not apply all changes requested by the Rojo server:\n{}", - PatchSet.humanSummary(self.__instanceMap, unappliedPatch)) - end - - if self.__patchAppliedCallback then - pcall(self.__patchAppliedCallback, message, unappliedPatch) - end + return Promise.new(function(resolve, reject) + while self.__status == Status.Connected do + local success, result = self.__apiContext:retrieveMessages() + :andThen(function(messages) + if self.__status == Status.Disconnected then + -- In the time it took to retrieve messages, we disconnected + -- so we just resolve immediately without patching anything + return + end + + Log.trace("Serve session {} retrieved {} messages", tostring(self), #messages) + + for _, message in messages do + local unappliedPatch = self.__reconciler:applyPatch(message) + + if not PatchSet.isEmpty(unappliedPatch) then + Log.warn("Could not apply all changes requested by the Rojo server:\n{}", + PatchSet.humanSummary(self.__instanceMap, unappliedPatch)) + end + + if self.__patchAppliedCallback then + pcall(self.__patchAppliedCallback, message, unappliedPatch) + end + end + end):await() + + if self.__status == Status.Disconnected then + -- If we are no longer connected after applying, we stop silently + -- without checking for errors as they are no longer relevant + break + elseif success == false then + reject(result) end + end - if self.__status ~= Status.Disconnected then - return self:__mainSyncLoop() - end - end) + -- We are no longer connected, so we resolve the promise + resolve() + end) end function ServeSession:__stopInternal(err) From 7ad1f68c3f6de4ab8ed2a77a596b4d72afbf4db4 Mon Sep 17 00:00:00 2001 From: boatbomber Date: Fri, 14 Jul 2023 20:05:59 -0700 Subject: [PATCH 2/2] Let apicontext error bubble up since ServeSession now knows when to ignore it --- plugin/src/ApiContext.lua | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/plugin/src/ApiContext.lua b/plugin/src/ApiContext.lua index 98890d4f6..9a683dd55 100644 --- a/plugin/src/ApiContext.lua +++ b/plugin/src/ApiContext.lua @@ -11,13 +11,6 @@ local validateApiInfo = Types.ifEnabled(Types.ApiInfoResponse) local validateApiRead = Types.ifEnabled(Types.ApiReadResponse) local validateApiSubscribe = Types.ifEnabled(Types.ApiSubscribeResponse) ---[[ - Returns a promise that will never resolve nor reject. -]] -local function hangingPromise() - return Promise.new(function() end) -end - local function rejectFailedRequests(response) if response.code >= 400 then local message = string.format("HTTP %s:\n%s", tostring(response.code), response.body) @@ -212,12 +205,8 @@ function ApiContext:retrieveMessages() local function sendRequest() local request = Http.get(url) :catch(function(err) - if err.type == Http.Error.Kind.Timeout then - if self.__connected then - return sendRequest() - else - return hangingPromise() - end + if err.type == Http.Error.Kind.Timeout and self.__connected then + return sendRequest() end return Promise.reject(err)