diff --git a/src/routes/v2/pages/Tangent/services/remoteEnvHost.test.ts b/src/routes/v2/pages/Tangent/services/remoteEnvHost.test.ts index 684d01b04..70bc70163 100644 --- a/src/routes/v2/pages/Tangent/services/remoteEnvHost.test.ts +++ b/src/routes/v2/pages/Tangent/services/remoteEnvHost.test.ts @@ -139,6 +139,50 @@ describe("createRemoteEnvHost", () => { await expect(connection).resolves.toBeUndefined(); }); + it("reports reconnect errors once per outage and resets after recovery", async () => { + const { host, onError } = connectedHost(makeWorker()); + const connect = client.socket.on.mock.calls.find( + ([event]) => event === "connect", + )![1]; + const error = client.socket.on.mock.calls.find( + ([event]) => event === "connect_error", + )![1]; + connect(); + error(new Error("websocket error")); + error(new Error("xhr poll error")); + error(new Error("websocket error")); + expect(onError).toHaveBeenCalledTimes(1); + expect(onError).toHaveBeenCalledWith( + "Tangent editor control failed to reconnect: websocket error", + ); + + connect(); + error(new Error("xhr poll error")); + expect(onError).toHaveBeenCalledTimes(2); + + host.disconnect(); + error(new Error("stale connection")); + expect(onError).toHaveBeenCalledTimes(2); + }); + + it("still rejects initial connection failures", async () => { + const onError = vi.fn(); + const host = createRemoteEnvHost({ + url: "http://localhost:8000", + worker: makeWorker() as unknown as Remote, + onError, + }); + const connection = host.connect("token", "env-1"); + const error = client.socket.on.mock.calls.find( + ([event]) => event === "connect_error", + )![1]; + error(new Error("xhr poll error")); + await expect(connection).rejects.toThrow( + "Tangent editor control failed to connect: xhr poll error", + ); + expect(onError).not.toHaveBeenCalled(); + }); + it("forwards host metadata into the connect options", () => { const worker = makeWorker(); const metadata = { diff --git a/src/routes/v2/pages/Tangent/services/remoteEnvHost.ts b/src/routes/v2/pages/Tangent/services/remoteEnvHost.ts index af798c717..719cc96f9 100644 --- a/src/routes/v2/pages/Tangent/services/remoteEnvHost.ts +++ b/src/routes/v2/pages/Tangent/services/remoteEnvHost.ts @@ -447,6 +447,7 @@ export function createRemoteEnvHost( const connection = new Promise((resolve, reject) => { let connected = nextClient.socket.connected; + let reconnectErrorReported = false; // Settle rather than return when a newer connection (or a disconnect) // has taken over: the caller awaits this before scheduling the next @@ -458,6 +459,7 @@ export function createRemoteEnvHost( return; } connected = true; + reconnectErrorReported = false; resolve(); }); nextClient.socket.on("connect_error", (error: Error) => { @@ -473,9 +475,12 @@ export function createRemoteEnvHost( ); return; } - onError?.( - `Tangent editor control failed to reconnect: ${error.message}`, - ); + if (!reconnectErrorReported) { + reconnectErrorReported = true; + onError?.( + `Tangent editor control failed to reconnect: ${error.message}`, + ); + } }); if (connected) resolve();