Implement exponential backoff for reconnections

Closes: https://todo.sr.ht/~emersion/gamja/118
This commit is contained in:
Simon Ser 2021-12-07 13:05:42 +01:00
parent ab3d4dd661
commit f81c564d23

View file

@ -25,7 +25,8 @@ const permanentCaps = [
"soju.im/bouncer-networks",
];
const RECONNECT_DELAY_SEC = 10;
const RECONNECT_MIN_DELAY_MSEC = 10 * 1000; // 10s
const RECONNECT_MAX_DELAY_MSEC = 10 * 60 * 1000; // 10min
// WebSocket status codes
// https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4.1
@ -64,6 +65,38 @@ class IRCError extends Error {
}
}
/**
* Implements a simple exponential backoff.
*/
class Backoff {
n = 0;
constructor(min, max) {
this.min = min;
this.max = max;
}
reset() {
this.n = 0;
}
next() {
if (this.n === 0) {
this.n = 1;
return this.min;
}
let dur = this.n * this.min;
if (dur > this.max) {
dur = this.max;
} else {
this.n *= 2;
}
return dur;
}
}
export default class Client extends EventTarget {
static Status = {
DISCONNECTED: "disconnected",
@ -95,6 +128,7 @@ export default class Client extends EventTarget {
batches = new Map();
autoReconnect = true;
reconnectTimeoutID = null;
reconnectBackoff = new Backoff(RECONNECT_MIN_DELAY_MSEC, RECONNECT_MAX_DELAY_MSEC);
pingIntervalID = null;
pendingCmds = {
WHO: Promise.resolve(null),
@ -171,11 +205,12 @@ export default class Client extends EventTarget {
};
window.addEventListener("online", handleOnline);
} else {
console.info("Reconnecting to server in " + RECONNECT_DELAY_SEC + " seconds");
let delay = this.reconnectBackoff.next();
console.info("Reconnecting to server in " + (delay / 1000) + " seconds");
clearTimeout(this.reconnectTimeoutID);
this.reconnectTimeoutID = setTimeout(() => {
this.reconnect();
}, RECONNECT_DELAY_SEC * 1000);
}, delay);
}
}
});
@ -210,6 +245,8 @@ export default class Client extends EventTarget {
console.log("Connection opened");
this.setStatus(Client.Status.REGISTERING);
this.reconnectBackoff.reset();
this.nick = this.params.nick;
this.send({ command: "CAP", params: ["LS", "302"] });