MatrixAI / js-ws

Websocket Transport Library for TypeScript/JavaScript Applications

Home Page:https://polykey.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Bi-Directional Keep-Alive Initiation

amydevs opened this issue · comments

Specification

On the WebSocketConnection there are two variables that govern the Keep-Alive:

  • keepAliveIntervalTime - The time interval between which pings are sent (note that this is also the amount of time that needs to have elapsed for the first ping to be sent by a client or server after establishing a WebSocketConnection)
  • keepAliveTimeoutTime - The maximum time interval between receiving pings (or messages), otherwise timeout

The keep-alive will need to be able to be initiated both on the client-side or the server-side.

How this will be implemented is that:

  • client and server both start pinging initially
  • if the client receives a ping, stop pinging
  • if the server receives a ping, keep pinging
  • if the server receives two pings, stop pinging
  • if either a client or a server receives a ping or data, their next scheduled ping is rescheduled to be now + keepAliveIntervalTime
  • both the server and client must pong on receiving a ping

This will mean that both the client and the server can establish keep-alive responsibility.

It is important to note that on a browser window.WebSocket instance, pings and pongs are abstracted away. The browser will automatically respond to any pings from a server with a pong, but are assumed to never send any pings. The reason that the server will only stop pinging after receiving to pings is so that in case a browser implementation unreliably pings, there is less chance for the connection to timeout as the server requires a second ping for confirmation that the client takes the responsibility of pinging.

Client Initiated Keep-Alive:

Untitled-2023-06-09-1740 excalidraw(8)

In this case, both the client and the server are able to send pings. This would occur in the circumstance where both the server and client are in a node context. The client schedules a ping to be sent on the first second, but the server schedules a ping to be on 2 seconds. The server receives a ping before it's own ping can be sent. So at the 1st second, the server reschedules its ping to be sent on the 3rd second. However, the client sends a second ping on the 2nd second and establishes responsibility for Keep-Alive, and the server cancels its scheduled ping.

Server Initiated Keep-Alive:

Untitled-2023-06-09-1740 excalidraw(6)

In this case, either the client is a browser or the keepAliveIntervalTime of the client is longer than that of the server. That means the client receives a ping before their scheduled ping is sent, cancelling it.

if the keepAliveIntervalTime on a client is less than that of the server, the client can eagerly ping twice to establish keepalive responsibility before the server is ever able to ping. This is because the the server's scheduled ping is reset after every ping the server is received, so that the server is never able to send a ping before the client establishes responsibility. This will be the case unless the server immediately starts sending data to the client, as the client's ping will be continuously refreshed, allowing the server to take responsibility for Keep-Alive. This is okay, as responsibility should be based on urgency rather than being deterministic.

Additional context

Tasks

  • 1. Implement

What if both sides ping on their own interval, but if a side receives a ping it refreshes it's ping delay. That way the one that sends first or has a smaller interval should have priority when pinging. The other side will only ping again if its ping delay wasn't refreshed by receiving a ping.

What if both sides ping on their own interval, but if a side receives a ping it refreshes it's ping delay. That way the one that sends first or has a smaller interval should have priority when pinging. The other side will only ping again if its ping delay wasn't refreshed by receiving a ping.

That is a good point ty

As discussed yesterday the solution should be quite simple here.

Both the interval timer and timeout timer refresh as soon as they receive any data from the peer, whether that is a data, or a ping.

Whenever you get a ping, you send out a pong no matter what.

The ping interval will run and execute even if you're continuously sending data, with no response from the other side.

Then whichever one has the lowest ping interval or sends data first will generally be the one doing the pinging. Both sides may naturally take turns on who is doing the pinging depending on which side becomes more of a sender compared the other side.

This algorithm is co-ordination less and achieves the main goal of the keep alive system - keeping the connection alive.

I believe this is done by #5 now, reopen if not @amydevs.

commented

I believe this is done by #5 now, reopen if not @amydevs.

The keepalive on staging is still currently on both sides ping regardless, i'll change this asap

commented

fixed by commit a694f4c