コンテンツにスキップ

WebSocketヒバーネーションを使用したWebSocketサーバーの構築

Durable ObjectsとWorkersを使用してWebSocketヒバーネーションを利用したWebSocketサーバーを構築します。

この例は、WebSocketサーバーの構築の例に似ていますが、WebSocketヒバーネーションAPIを使用しています。WebSocketヒバーネーションAPIは、Durable Objects上に構築されたWebSocketサーバーアプリケーションに推奨されます。これは、料金の発生時間を大幅に減少させ、WebSocketアプリケーションと相性の良い追加機能を提供するためです。詳細については、WebSocketsでDurable Objectsを使用するを参照してください。

import { DurableObject } from "cloudflare:workers";
// Worker
export default {
async fetch(request, env, ctx) {
if (request.url.endsWith("/websocket")) {
// WebSocketアップグレードリクエストを受け取ることを期待します。
// もしあれば、リクエストを受け入れ、WebSocketレスポンスを返します。
const upgradeHeader = request.headers.get('Upgrade');
if (!upgradeHeader || upgradeHeader !== 'websocket') {
return new Response('Durable Object expected Upgrade: websocket', { status: 426 });
}
// この例は、名前「foo」がハードコーディングされているため、
// 同じDurable Objectインスタンスを参照します。
let id = env.WEBSOCKET_HIBERNATION_SERVER.idFromName("foo");
let stub = env.WEBSOCKET_HIBERNATION_SERVER.get(id);
return stub.fetch(request);
}
return new Response(null, {
status: 400,
statusText: 'Bad Request',
headers: {
'Content-Type': 'text/plain',
},
});
}
};
// Durable Object
export class WebSocketHibernationServer extends DurableObject {
async fetch(request) {
// WebSocket接続の2つの端を作成します。
const webSocketPair = new WebSocketPair();
const [client, server] = Object.values(webSocketPair);
// `acceptWebSocket()`を呼び出すことで、このWebSocketがDurable Object内でリクエストを終了することを
// ランタイムに通知します。これは接続を「受け入れる」効果があり、
// WebSocketがメッセージを送受信できるようにします。
// `ws.accept()`とは異なり、`state.acceptWebSocket(ws)`はWebSocketが「ヒバーネート可能」であることを
// Workersランタイムに通知するため、接続がオープンの間、Durable Objectをメモリに固定する必要がありません。
// 非アクティブな期間中、Durable Objectはメモリから追い出される可能性がありますが、
// WebSocket接続はオープンのままです。後でWebSocketがメッセージを受信した場合、
// ランタイムはDurable Objectを再作成し(`constructor`を実行し)、メッセージを適切なハンドラーに配信します。
this.ctx.acceptWebSocket(server);
return new Response(null, {
status: 101,
webSocket: client,
});
}
async webSocketMessage(ws, message) {
// クライアントからメッセージを受信した際、同じメッセージで応答しますが、
// メッセージの前に「[Durable Object]: 」を付け加え、接続の総数を返します。
ws.send(`[Durable Object] message: ${message}, connections: ${this.ctx.getWebSockets().length}`);
}
async webSocketClose(ws, code, reason, wasClean) {
// クライアントが接続を閉じた場合、ランタイムはwebSocketClose()ハンドラーを呼び出します。
ws.close(code, "Durable Object is closing WebSocket");
}
}

最後に、wrangler.tomlファイルを構成して、選択した名前空間とクラス名に基づいてDurable Objectのバインディングマイグレーションを含めます。

name = "websocket-hibernation-server"
[[durable_objects.bindings]]
name = "WEBSOCKET_HIBERNATION_SERVER"
class_name = "WebSocketHibernationServer"
[[migrations]]
tag = "v1"
new_classes = ["WebSocketHibernationServer"]

関連リソース