Skip to content

Commit a4f8d86

Browse files
committed
Reconnect the WebSocket if we disconnect uncleanly
1 parent a503e74 commit a4f8d86

File tree

1 file changed

+54
-26
lines changed

1 file changed

+54
-26
lines changed

ui/frontend/websocketMiddleware.ts

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -41,38 +41,66 @@ const openWebSocket = (currentLocation: Location) => {
4141
}
4242
}
4343

44+
// https://exponentialbackoffcalculator.com
45+
const backoffMs = (n: number) => Math.min(100 * Math.pow(2, n), 10000);
46+
4447
export const websocketMiddleware = (window: Window): Middleware => store => {
45-
const socket = openWebSocket(window.location);
48+
let socket: WebSocket | null = null;
49+
let wasConnected = false;
50+
let reconnectAttempt = 0;
4651

47-
if (socket) {
48-
socket.addEventListener('open', () => {
49-
store.dispatch(websocketConnected());
50-
});
52+
const connect = () => {
53+
socket = openWebSocket(window.location);
5154

52-
socket.addEventListener('close', () => {
53-
store.dispatch(websocketDisconnected());
54-
});
55+
if (socket) {
56+
socket.addEventListener('open', () => {
57+
store.dispatch(websocketConnected());
5558

56-
socket.addEventListener('error', () => {
57-
// We cannot get detailed information about the failure
58-
// https://stackoverflow.com/a/31003057/155423
59-
const error = 'Generic WebSocket Error';
60-
store.dispatch(websocketError(error));
61-
reportWebSocketError(error);
62-
});
59+
wasConnected = true;
60+
});
6361

64-
// TODO: reconnect on error? (if ever connected? if < n failures?)
62+
socket.addEventListener('close', (event) => {
63+
store.dispatch(websocketDisconnected());
6564

66-
socket.addEventListener('message', (event) => {
67-
try {
68-
const rawMessage = JSON.parse(event.data);
69-
const message = WSMessageResponse.parse(rawMessage);
70-
store.dispatch(message);
71-
} catch (e) {
72-
console.log('Unable to parse WebSocket message', event.data, e);
73-
}
74-
});
75-
}
65+
// Reconnect if we've previously connected
66+
if (wasConnected && !event.wasClean) {
67+
wasConnected = false;
68+
reconnectAttempt = 0;
69+
reconnect();
70+
}
71+
});
72+
73+
socket.addEventListener('error', () => {
74+
// We cannot get detailed information about the failure
75+
// https://stackoverflow.com/a/31003057/155423
76+
const error = 'Generic WebSocket Error';
77+
store.dispatch(websocketError(error));
78+
reportWebSocketError(error);
79+
});
80+
81+
socket.addEventListener('message', (event) => {
82+
try {
83+
const rawMessage = JSON.parse(event.data);
84+
const message = WSMessageResponse.parse(rawMessage);
85+
store.dispatch(message);
86+
} catch (e) {
87+
console.log('Unable to parse WebSocket message', event.data, e);
88+
}
89+
});
90+
}
91+
};
92+
93+
const reconnect = () => {
94+
if (socket && socket.readyState == socket.OPEN) { return; }
95+
96+
connect();
97+
98+
const delay = backoffMs(reconnectAttempt);
99+
reconnectAttempt += 1;
100+
setTimeout(reconnect, delay);
101+
};
102+
103+
connect();
76104

77105
return next => action => {
78106
if (socket && socket.readyState == socket.OPEN && sendActionOnWebsocket(action)) {

0 commit comments

Comments
 (0)