learningequality / learningequality/studio

Websocket message acknowledgement and maintenance

Open
#3,630 2 comments 0 reactions 1 assignee View on GitHub

@ozer550 is already working on this.

Since Jan 10, 2023.

DEV: backend DEV: frontend Feature TAG: new feature TAG: performance
Dominant language
Python
Stars
191
Forks
307
Avg merge
5d 6h
Merged PRs (30d)
10

Description

Current behavior

With @ozer550's awesome work on introducing websockets to Kolibri Studio, there's some opportunity for refinement on managing the communication with the backend over the websocket. Unfortunately, we didn't get a production-like server running until late in the project, so this proposal comes from testing in that environment as a post-project follow-up. This proposal would also reduce risk of critical bugs that could cripple editing functionality, and could serve as an ease of transition when we deploy websockets to production

  • Currently, if the websocket gets closed, the frontend does not robustly handle it and requires you to refresh the page
  • The connection could timeout from becoming idle
  • The websocket message structure isn't standardized

Some insights:

  • Google's Load Balancer timeout is 30 seconds so after 30 seconds, an idle websocket connection would be closed
  • Cloudflare's timeout is 100 seconds, and would similarly close an idle connection

Proposal

  • First, define a message structure with fields that can be used to provide integrity of the websocket message communication
    • An example lending some inspiration from TCP might be something like:
    {
      "id": "abc...123", // unique message id
      "type": "ACK", // type of message, perhaps SYN=synchronize, ACK=acknowledge, PNG=ping?
      "payload": { ... }, // existing request or response data
    }
    
  • Define a timeout, 15 seconds? 25 seconds?

Desired behavior

  • A new JS class, sync class, should be defined to abstract away the syncing of changes over HTTP API or Websockets
  • The sync class can emit events when it receives changes, successes, allowed, disallowed, etc. and corresponding handle* functions can be attached as listeners
    • handleMaxRevs could be attached to the 3 events changes, successes, and errors
  • The sync class should have a send method accepting a payload to send
  • Every websocket message sent from the client should be ACKnowledged by the server
    • The server's response would still occur as a post-ack SYN message
    • The server would acknowledge with the message ID
  • The client sends periodic PNG messages to keep connection from going idle
    • Send ping messages every timeout seconds
  • If a ping message is not acknowledged after timeout seconds the connection
    • The sync class should handle fallback to the HTTP API with new messages
    • The sync class should re-ping on receiving new messages to send, up to two times (3 unacknowledged pings), while falling back to the HTTP API until an acknowledged ping is received
    • Pinging should always be timeout seconds after last acknowledged message
  • The sync class should wait until receiving the response SYN message before SYNchronizing more changes
    • This wait time should be timeout seconds, meaning at most, a full request to response could wait up to 2 x timeout seconds, since the client would first receive the ACK message up to timeout seconds after sending
  • Track to Sentry or Google Analytics each time a websocket fails, so that we can tune and simplify this in the future

Value add

  • Stability as we roll out websockets to production
  • Robust communication over websocket or HTTP API

Possible tradeoffs

  • The message acknowledgement and associated work may be overkill, since we already have similar features represented in the change handling, but it does allow us to manage issues with the websocket connection separately from the changes and that architecture

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.