From d00cf3a9c3ec31a7200634889b3afed774be11c3 Mon Sep 17 00:00:00 2001 From: Ayane Satomi Date: Mon, 23 Oct 2023 09:09:00 +0000 Subject: [PATCH 1/4] Make server not send anything if socket state is anything but open --- routes/index.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/routes/index.tsx b/routes/index.tsx index 3fdc495..a54f164 100644 --- a/routes/index.tsx +++ b/routes/index.tsx @@ -20,7 +20,7 @@ export const handler: Handlers = { GET: async (req, ctx) => { let bc = new BroadcastChannel("global-count"); - // check if we're requesting wss:// or ws://, add the response header accordingly + // check if we're requesting wss:// or ws://, then upgrade as necessary if (req.headers.get("upgrade") === "websocket") { const { socket, response } = Deno.upgradeWebSocket(req); @@ -34,7 +34,12 @@ export const handler: Handlers = { }; bc.addEventListener("message", (e) => { - socket.send(JSON.stringify({ globalCount: e.data })); + try { + // don't send if the socket is closed + if (socket.readyState === 1) socket.send(JSON.stringify({ globalCount: e.data })); + } catch (e) { + console.warn(`[${new Date().toISOString()}] ${e.stack}`); + } }); socket.onclose = () => { From 2ab8369d4e59a0d7291c5f28877a3e5291c3adb5 Mon Sep 17 00:00:00 2001 From: Ayane Satomi Date: Mon, 23 Oct 2023 10:04:13 +0000 Subject: [PATCH 2/4] Gracefully handle network interruptions --- islands/CounterCard.tsx | 56 ++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/islands/CounterCard.tsx b/islands/CounterCard.tsx index d39709d..c8e71cc 100644 --- a/islands/CounterCard.tsx +++ b/islands/CounterCard.tsx @@ -89,7 +89,9 @@ export default function Counter(props: SharedProps) { JSON.stringify({ data: internalCount + 1 }), ); console.info( - `[${new Date().toISOString()}] Updating global count: ${internalCount + 1}`, + `[${new Date().toISOString()}] Updating global count: ${ + internalCount + 1 + }`, ); setInternalCount(0); } @@ -99,24 +101,50 @@ export default function Counter(props: SharedProps) { useEffect(() => { let ws = new WebSocket(window.location.href.replace("http", "ws")); - ws.addEventListener("open", () => { - console.log(`[${new Date().toISOString()}] Connected to statistics socket`); - }); + ws.onopen = () => { + console.log( + `[${new Date().toISOString()}] Connected to statistics socket`, + ); + }; - ws.addEventListener("message", (e) => { - console.log(`[${new Date().toISOString()}] Received global count: ${e.data}`); + ws.onmessage = (e) => { + console.log( + `[${new Date().toISOString()}] Received global count: ${e.data}`, + ); const data = JSON.parse(e.data); setGlobalCount(BigInt(parseInt(data.globalCount))); + }; + + ws.onclose = () => { + console.warn(`[${new Date().toISOString()}] Disconnected from statistics socket.`,); + }; + + ws.onerror = (e) => { + console.error(`[${new Date().toISOString()}] Socket Errored. Aggressively reconnecting...`,); + ws = new WebSocket(window.location.href.replace("http", "ws")); + }; + + const onlineHandler = () => { + console.log("Client detected online, resuming connection."); + ws = new WebSocket(window.location.href.replace("http", "ws")); + }; + + const offlineHandler = () => { + console.warn("Client detected offline!"); + ws.close(); + }; + + globalThis.window.addEventListener("online", onlineHandler); + globalThis.window.addEventListener("offline", offlineHandler); + globalThis.window.addEventListener("beforeunload", () => { + ws.close(); }); - ws.addEventListener("error", () => { - console.warn( - `[${new Date().toISOString()}] Disconnected from statistics socket, attempting to reconnect...`, - ); - const backoff = 1000 + Math.random() * 5000; - new Promise((resolve) => setTimeout(resolve, backoff)); - ws = new WebSocket(window.location.href.replace("http", "ws")); - }) + return () => { + globalThis.window.removeEventListener("online", onlineHandler); + globalThis.window.removeEventListener("offline", offlineHandler); + ws.close(); + }; }, []); return ( From d46adc06c5e368c0ecc614569da52c082fb4a3be Mon Sep 17 00:00:00 2001 From: Ayane Satomi Date: Mon, 23 Oct 2023 10:16:08 +0000 Subject: [PATCH 3/4] re-set connection handlers on reconnection --- islands/CounterCard.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/islands/CounterCard.tsx b/islands/CounterCard.tsx index c8e71cc..d8828e1 100644 --- a/islands/CounterCard.tsx +++ b/islands/CounterCard.tsx @@ -98,9 +98,7 @@ export default function Counter(props: SharedProps) { }, 5000)); }; - useEffect(() => { - let ws = new WebSocket(window.location.href.replace("http", "ws")); - + const handleWSEvents = (ws: WebSocket) => { ws.onopen = () => { console.log( `[${new Date().toISOString()}] Connected to statistics socket`, @@ -123,10 +121,16 @@ export default function Counter(props: SharedProps) { console.error(`[${new Date().toISOString()}] Socket Errored. Aggressively reconnecting...`,); ws = new WebSocket(window.location.href.replace("http", "ws")); }; + } + + useEffect(() => { + let ws = new WebSocket(window.location.href.replace("http", "ws")); + handleWSEvents(ws); const onlineHandler = () => { console.log("Client detected online, resuming connection."); ws = new WebSocket(window.location.href.replace("http", "ws")); + handleWSEvents(ws); }; const offlineHandler = () => { From 4ddc835f93f5816a525cde5251fc2366d417bfe0 Mon Sep 17 00:00:00 2001 From: Ayane Satomi Date: Mon, 23 Oct 2023 10:18:31 +0000 Subject: [PATCH 4/4] Gracefully log errors instead of trying something stupid here --- islands/CounterCard.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/islands/CounterCard.tsx b/islands/CounterCard.tsx index d8828e1..363d31a 100644 --- a/islands/CounterCard.tsx +++ b/islands/CounterCard.tsx @@ -118,8 +118,7 @@ export default function Counter(props: SharedProps) { }; ws.onerror = (e) => { - console.error(`[${new Date().toISOString()}] Socket Errored. Aggressively reconnecting...`,); - ws = new WebSocket(window.location.href.replace("http", "ws")); + console.error(`[${new Date().toISOString()}] Socket Errored. ${e.type}`,); }; }