fix(wsrouter): ensure no message reply is lost#906
Open
FrogTheFrog wants to merge 1 commit into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Please tick as appropriate:
If you're wanting to update a translation or add a new one, please use the weblate page: https://weblate.werwolv.net/projects/decky/
Description
Motivation
My plugin MoonDeck is experiencing issues once on a blue moon, where the UI gets stuck. This happens, because I queue promises to optimize some calls to backend python script. Sometimes after SteamDeck wakes up, the promise queue gets stuck, because the call to the backend is never resolved and the plugin must then be reloaded.
When Decky loses WebSocket connection, all of the running calls are left in an unresolved state, because the backend never sends the reply to the frontend anymore. I do not know if this solves my issue completely (was not able to confirm that this is the root cause since it so rare), however Decky should not just leave promises in a "forever-unresolved" state while the plugin is still active.
New call-reply protocol
The existing protocol has been extended with new message types:
DISCARDRECEIVED_RESPONSEFULL_SYNCWhen the connection is first established (or re-established), a
FULL_SYNCmessage is sent with ALL of previously submitted calls, but which did not get a reply yet. When backend receives such a message it will:RECEIVED_RESPONSEmessage, more on the later), the backend will simply cleanup the cache.When the frontend receives a response (either
ERROR,REPLYorDISCARD), it will always reply withRECEIVED_RESPONSE, so that the backend may cleanup its response cache. This way:backend -> frontend, we will still get it afterFULL_SYNC, because the response cache would still contain it.RECEIVED_RESPONSEis lost fromfrontend -> backend, theFULL_SYNCwill cleanup the cache on backend.Finally, the
DISCARDmessage is used to notify the frontend to just cleanup its cache without resolving the promise (for garbage-collection). At the moment it is only done for pending plugin calls whose python backend is being unloaded and they would never be resolved. We could send anERROR, but then not every plugin is gracefully handling such errors (if errors are handled at all).Testing
I've manually made the Decky close the websocket every 30 seconds and confirmed that before the fix, the promises would get stuck when plugin backend is still generating a reply when the socked closes.
With this fix, it never happens again and cached replies are sent back once the connection is restored.
Additionally, I disabled/enabled and reloaded the plugin while this was happening and have confirmed that the
DISCARDmessage is being sent accordingly for plugin replies where plugin is still "thinking". Verified that such replied do not throw any exception in the frontend.