fix: use Hibernation API for reliable WebSocket broadcast

Replace manual session tracking with Cloudflare's Hibernation API
so WebSocket connections survive Durable Object eviction.
This commit is contained in:
2026-04-16 20:51:47 +07:00
parent 50f4365034
commit eef6879ff2
+19 -15
View File
@@ -1,12 +1,10 @@
/**
* Durable Object for WebSocket broadcast room.
* All connected clients receive pixel updates in real-time.
* Uses Hibernation API so connections survive DO eviction.
*/
export class CanvasRoom {
constructor(state) {
this.state = state;
/** @type {Set<WebSocket>} */
this.sessions = new Set();
}
async fetch(request) {
@@ -16,11 +14,11 @@ export class CanvasRoom {
if (url.pathname === '/broadcast' && request.method === 'POST') {
const pixels = await request.json();
const message = JSON.stringify({ type: 'pixels', pixels });
for (const ws of this.sessions) {
for (const ws of this.state.getWebSockets()) {
try {
ws.send(message);
} catch {
this.sessions.delete(ws);
ws.close(1011, 'send failed');
}
}
return new Response('ok');
@@ -30,17 +28,23 @@ export class CanvasRoom {
const pair = new WebSocketPair();
const [client, server] = Object.values(pair);
server.accept();
this.sessions.add(server);
server.addEventListener('close', () => {
this.sessions.delete(server);
});
server.addEventListener('error', () => {
this.sessions.delete(server);
});
this.state.acceptWebSocket(server);
return new Response(null, { status: 101, webSocket: client });
}
/** Called when a WebSocket receives a message (required by Hibernation API) */
webSocketMessage(ws, message) {
// Clients don't send messages in this protocol; ignore.
}
/** Called when a WebSocket is closed */
webSocketClose(ws, code, reason, wasClean) {
ws.close(code, reason);
}
/** Called on WebSocket error */
webSocketError(ws, error) {
ws.close(1011, 'error');
}
}