From 1ee129176eb71f5e246462b66fd9c9862ed1ee7a Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Tue, 8 Apr 2025 19:50:14 -0400 Subject: Restart the event connection if heartbeats stop showing up. The changes introduced in the previous commit make it possible to detect lost connections and restart them, so do so. The process is pretty simple - a new remote state is spun up using `/api/boot`, swapped in for the existing state, and a `new EventSource` is started from that new remote state to consume events. This can induce some anomalies. For example, messages that arrive on the server between the loss of one connection and the creation of the next one just "show up" in boot, without ever appearing in the event stream. (This is technically also true on client startup, but it's easier to expect in that situation.) This is something we'll need to consider when implementing things like notifications or unread flags, though the ones we have today, which are state-based, do work fine. By design, this _does not_ retry either the `/api/boot` call or the new event source setup. Event sources will try to reconnect on their own, up to a point, so that's fine, but we need to build something more robust for `/api/boot`. I want to tackle that separately from detecting lost connections and reacting to them, but that does mean that this is not a complete solution to client reconnects. --- ui/lib/watchdog.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 ui/lib/watchdog.js (limited to 'ui/lib/watchdog.js') diff --git a/ui/lib/watchdog.js b/ui/lib/watchdog.js new file mode 100644 index 0000000..c95fd4d --- /dev/null +++ b/ui/lib/watchdog.js @@ -0,0 +1,27 @@ +export class Watchdog { + constructor(onExpired) { + this.timeout = null; + this.onExpired = onExpired; + } + + reset(delay) { + if (this.timeout !== null) { + clearTimeout(this.timeout); + } + this.timeout = setTimeout(this.expire.bind(this), delay); + } + + stop() { + if (this.timeout !== null) { + clearTimeout(this.timeout); + this.timeout = null; + } + } + + expire() { + if (this.timeout !== null) { + this.timeout = null; + } + this.onExpired(); + } +} -- cgit v1.2.3