Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add info on websockets #2189

Merged
merged 5 commits into from
Dec 8, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions client/src/websocket/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# WebSocket

WebSocket allows bi-directional communication between the UI server and the UI client.
In our infrastructure, the client sends messages with a specific structure that the
server interprets as instructions. Most of the time, the instructions start a loop
that performs actions on behalf of the user at specific intervals (5 seconds or 3
minutes).

You can find more details on the [server side section](../../../server/src/websocket/) about WebSockets.

## Disconnections

The WebSocket channels are now reasonably stable, staying alive for hours.
Still, it's good practice to consider the connection unstable when developing new code
involving WebSockets. This means the code should handle connections being temporarily
interrupted and re-created.

## Issues

We had issues with WebSockets channels being dropped after a few minutes. Intervals were irregular, with an average duration between 5 and 10 minutes.

In RenkuLab, we have a complex network topology; an incoming connection goes through:
* [HAproxy](https://www.haproxy.com): load balancing the incoming connections.
* Namespace-wide [Nginx](https://www.nginx.com): routing the requests from the outer
network to local pods.
* UI [Nginx](https://www.nginx.com): serving the UI responses

It turned out we had to modify a setting on the namespace Nginx to keep connections
alive for longer, precisely the `worker_shutdown_timeout` setting
([reference](https://github.com/kubernetes/ingress-nginx/issues/2461)).
We decided to raise it, aiming to keep connections alive for ~12 hours.
39 changes: 23 additions & 16 deletions server/src/websocket/README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
# WebSocket

WebSocket allows the UI server to push notifications directly to the UI client through a
bi-directional communication channel after an initial setup that helps in identifying the
user.
bi-directional communication channel after an initial setup that helps identify the user.

This way, we can remove inefficient polling systems to keep an up-to-date status of some
resources. In the first iteration, this will be limited to moving the polling logic from the
client to the server with little changes. Ideally, we will later rely more on server events
generated by the backend services, removing polling entirely.
Our current implementation relies on the client opening the connection and sending commands
that can be interpreted by the server (thorugh an extensible system)[#-extend-the-supported-commands]. When needed, the server can repeat actions on behalf
of the user every 5 seconds or 3 minutes, and cache some data locally.

WebSocket also simplifies notifications. We already have a raw system for that in the client,
and after updating it, we could use it more extensively and ensure the content shown on all
pages won't become stale without notifying the user.
This way, we can remove client-side polling functions and improve the client reactivity
to backend changes, preventing the interface from showing stale content without
appropriately notifying the user.

## Why WebSocket?

Expand All @@ -25,7 +23,7 @@ resources the user wants to access.

## Authentication

The authentication can only be done while establishing the connection. This is not a big
Authentication can only be done while establishing the connection. This is currently not a big
deal for the UI server, considering it manages the access tokens on behalf of the users.
At each cycle/request, we can verify whether the tokens are still valid or not, and either
proceed or send an error message and close the channel.
Expand Down Expand Up @@ -95,13 +93,22 @@ Additional handlers can be added to either the `longLoopFunctions` or
Ideally, for each supported command, there should be a handler function for the
setup phase and a loop function repeated for each iteration of the relevant loop.
Any relevant data is currently cached locally, but Redis support can easily be
added if we require it.

added if required.
Please avoid overlapping the setup logic with the iteration logic to keep functions
simple and readable. This means the setup should prepare data for the iteration function,
and the iteration function should handle recurring action (typically fetching from remote).

## Handle multiple tabs/sessions

Since each loop sends requests to back-end services on behalf of the user, we want to limit them
to the minimum. This requires a strategy to handle multiple tabs in a single loop.
Since each loop sends requests to back-end services on behalf of the user, we want
to limit them to the minimum. This requires a strategy to handle multiple tabs in a
single loop.
WebSocket channels are handled per user, and each time a new channel is added, the
server sends the same notification to each of them. When the last user's channel is removed,
the loop stops.
server sends the same notification to each of them. When the last user's channel is
removed, the loop stops.
We should implement a strategy to redirect all the user requests from the same user
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would make sense to add a link to #2184 here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes! Added

to the same instance of the the server (sticky sessions, see
[#2184](https://github.com/SwissDataScienceCenter/renku-ui/issues/2184)).

## Client side
See the [client side section](../../../client/src/websocket/) for details on how the client uses WebSockets.