Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

はじめに

最終更新 Markdown で表示Agent セットアップ

このガイドでは、次の作業を順に進めます。

  • Durable Object を定義する JavaScript クラスを書く。
  • Durable Objects SQL API で、Durable Object 専用の組み込み SQLite データベースを照会する。
  • 別の Worker から Durable Object をインスタンス化し、通信する。
  • Durable Object と、その Durable Object と通信する Worker をデプロイする。

Durable Objects の詳細は What are Durable Objects? を参照してください。

クイックスタート

手順を飛ばしてすぐに始めたい場合は、次のボタンを選びます。

Cloudflare にデプロイ

GitHub アカウントにリポジトリが作成され、アプリケーションが Cloudflare Workers へデプロイされます。Cloudflare Workers に慣れていて、手順ごとの案内を飛ばしたい場合に使います。

Cloudflare Workers が初めてなら、手順を手作業で進める方がよいことがあります。

前提条件

  1. Cloudflare アカウント に登録します。
  2. Node.js をインストールします。

Node.js のバージョンマネージャー

権限の問題を避け、Node.js のバージョンを切り替えられるよう、Voltanvm などの Node バージョンマネージャーを使います。このガイドの後半で説明する Wrangler には、Node バージョン 16.17.0 以降が必要です。

1. Worker プロジェクトを作成する

Durable Object には Worker からアクセスします。Worker アプリケーションは、Durable Object とやり取りするためのインターフェイスです。

Worker プロジェクトを作成するには、次を実行します。

npm create cloudflare@latest -- durable-object-starter

create cloudflare@latest を実行すると、Workers CLI である Wrangler がインストールされます。プロジェクトのテストとデプロイには Wrangler を使います。

セットアップでは、次のオプションを選びます。

  • What would you like to start with? では、Hello World example を選びます。
  • Which template would you like to use? では、Worker + Durable Objects を選びます。
  • Which language do you want to use? では、TypeScript を選びます。
  • Do you want to use git for version control? では、Yes を選びます。
  • Do you want to deploy your application? では、No を選びます(デプロイ前にいくつか変更します)。

新しいディレクトリが作成されます。コードを書く src/index.js または src/index.ts と、wrangler.jsonc 設定ファイルが含まれます。

新しいディレクトリへ移動します。

cd durable-object-starter

2. SQL API で Durable Object クラスを書く

Durable Object を作成してアクセスする前に、通常のエクスポートされた JavaScript クラスで振る舞いを定義する必要があります。

MyDurableObject クラスのコンストラクターには 2 つのパラメーターがあります。最初のパラメーター ctx には、その Durable Object 固有の状態(ストレージへアクセスするメソッドを含む)が入ります。2 番目のパラメーター env には、アップロード時に Worker へ関連付けたバインディングが入ります。

export class MyDurableObject extends DurableObject {
	constructor(ctx, env) {
		// Required, as we're extending the base class.
		super(ctx, env);
	}
}
export class MyDurableObject extends DurableObject<Env> {
	constructor(ctx: DurableObjectState, env: Env) {
		// Required, as we're extending the base class.
		super(ctx, env)
	}
}
from workers import DurableObject

class MyDurableObject(DurableObject):
    def __init__(self, ctx, env):
        super().__init__(ctx, env)

Worker は リモートプロシージャコール(RPC) で Durable Object と通信します。Durable Object クラスのパブリックメソッドは、別の Worker から呼び出せる RPC メソッド として公開されます。

ファイルは次のようになります。

export class MyDurableObject extends DurableObject {
	constructor(ctx, env) {
		// Required, as we're extending the base class.
		super(ctx, env);
	}

	async sayHello() {
		let result = this.ctx.storage.sql
			.exec("SELECT 'Hello, World!' as greeting")
			.one();
		return result.greeting;
	}
}
export class MyDurableObject extends DurableObject<Env> {
	constructor(ctx: DurableObjectState, env: Env) {
		// Required, as we're extending the base class.
		super(ctx, env)
	}

    async sayHello(): Promise<string> {
    	let result = this.ctx.storage.sql
    		.exec("SELECT 'Hello, World!' as greeting")
    		.one();
    	return result.greeting;
    }

}
from workers import DurableObject

class MyDurableObject(DurableObject):
    async def say_hello(self):
        result = self.ctx.storage.sql.exec(
            "SELECT 'Hello, World!' as greeting"
        ).one()

        return result.greeting

上記のコードでは、次を行っています。

  1. Worker から Durable Object と通信するために呼べる RPC メソッド sayHello() を定義しています。
  2. SQL API のメソッド(sql.exec())を ctx.storage 経由で使い、そのオブジェクトだけがアクセスできる専用の SQLite データベースである Durable Object のストレージにアクセスしています。
  3. one() で、クエリ結果がちょうど 1 行であることを確認し、その 1 行を表すオブジェクトを返しています。
  4. 行オブジェクトの greeting 列を返しています。

3. Durable Object をインスタンス化し、通信する

Durable Object へのアクセスには Worker を使います。Worker から Durable Object にアクセスする を参照してください。

Durable Object と通信するには、Worker の fetch ハンドラーを次のようにします。

export default {
	async fetch(request, env, ctx) {
		const stub = env.MY_DURABLE_OBJECT.getByName(new URL(request.url).pathname);

		const greeting = await stub.sayHello();

		return new Response(greeting);
	},
};
export default {
	async fetch(request, env, ctx): Promise<Response> {
    	const stub = env.MY_DURABLE_OBJECT.getByName(new URL(request.url).pathname);

    	const greeting = await stub.sayHello();

    	return new Response(greeting);
    },

} satisfies ExportedHandler<Env>;
from workers import handler, Response, WorkerEntrypoint
from urllib.parse import urlparse

class Default(WorkerEntrypoint):
    async def fetch(request):
        url = urlparse(request.url)
        stub = self.env.MY_DURABLE_OBJECT.getByName(url.path)
        greeting = await stub.say_hello()
        return Response(greeting)

上記のコードでは、次を行っています。

  1. HTTP リクエストを受け取る fetch() ハンドラーなど、Worker のメインイベントハンドラーをエクスポートしています。
  2. fetch() ハンドラーに env を渡しています。バインディングは、イベントハンドラーまたはクラスコンストラクターが呼ばれたときに 2 番目のパラメーターとして渡される環境オブジェクトのプロパティとして届きます。
  3. 指定した名前に基づいて Durable Object インスタンスのスタブを構築しています。スタブは、Durable Object へメッセージを送るためのクライアントオブジェクトです。
  4. Durable Object の RPC メソッド sayHello() を呼び出して Durable Object と通信し、Hello, World! という挨拶文字列を受け取っています。
  5. return new Response() で HTTP Response を構築し、クライアントへ HTTP レスポンスを返しています。

Durable Object との通信の詳細は Worker から Durable Object にアクセスする を参照してください。

4. Durable Object のバインディングを設定する

バインディング により、Worker は Cloudflare 開発者プラットフォーム上のリソースとやり取りできます。Worker プロジェクトの Wrangler 設定ファイル にある Durable Object バインディングには、バインディング名(このガイドでは MY_DURABLE_OBJECT)とクラス名(MyDurableObject)を含めます。

{
	"durable_objects": {
		"bindings": [
			{
				"name": "MY_DURABLE_OBJECT",
				"class_name": "MyDurableObject"
			}
		]
	}
}
[[durable_objects.bindings]]
name = "MY_DURABLE_OBJECT"
class_name = "MyDurableObject"

bindings セクションには次のフィールドがあります。

  • name - 必須。Worker 内で使うバインディング名です。
  • class_name - 必須。バインドするクラス名です。
  • script_name - 任意。デフォルトは、現在の 環境 の Worker コードです。

5. SQLite ストレージバックエンドで Durable Object クラスを設定する

Worker がエクスポートする各 Durable Object クラスは、Wrangler 設定ファイルの exports フィールドで宣言します。Cloudflare はこの宣言を使い、初回デプロイ時にクラスの名前空間をプロビジョニングし、以降のデプロイではライフサイクル(名前変更、削除、転送)を管理します。

SQLite ストレージを持つ新しい Durable Object クラスを登録する最小の exports ブロックは次のとおりです。

{
	"exports": {
		"MyDurableObject": {
			"type": "durable-object",
			"storage": "sqlite"
		}
	}
}
[exports.MyDurableObject]
type = "durable-object"
storage = "sqlite"

Durable Object クラスの宣言と管理の詳細は Durable Object クラスのエクスポート を参照してください。レガシーの migrations 配列を使っている既存の Worker がある場合は Durable Object クラスのマイグレーション(レガシー) を参照してください。

6. Durable Object Worker をローカルで開発する

Durable Object をローカルでテストするには、wrangler dev を実行します。

npx wrangler dev

コンソールに、Durable Object が返す Hello world 文字列が表示されます。

7. Durable Object Worker をデプロイする

Durable Object Worker をデプロイするには、次を実行します。

npx wrangler deploy

デプロイ後、Cloudflare ダッシュボードで作成した Durable Object Worker を確認できます。

Workers & Pages を開く ↗

Durable Object Worker は <YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev でプレビューできます。

まとめと最終コード

最終的なコードは次のようになります。

import { DurableObject } from "cloudflare:workers";
export class MyDurableObject extends DurableObject {
	constructor(ctx, env) {
		// Required, as we are extending the base class.
		super(ctx, env);
	}

	async sayHello() {
		let result = this.ctx.storage.sql
			.exec("SELECT 'Hello, World!' as greeting")
			.one();
		return result.greeting;
	}
}
export default {
	async fetch(request, env, ctx) {
		const stub = env.MY_DURABLE_OBJECT.getByName(new URL(request.url).pathname);

		const greeting = await stub.sayHello();

		return new Response(greeting);
	},
};
index.tsts
import { DurableObject } from "cloudflare:workers";
export class MyDurableObject extends DurableObject<Env> {
	constructor(ctx: DurableObjectState, env: Env) {
		// Required, as we are extending the base class.
		super(ctx, env)
	}

    async sayHello():Promise<string> {
    	let result = this.ctx.storage.sql
    		.exec("SELECT 'Hello, World!' as greeting")
    		.one();
    	return result.greeting;
    }

}
export default {
async fetch(request, env, ctx): Promise<Response> {
const stub = env.MY_DURABLE_OBJECT.getByName(new URL(request.url).pathname);

    	const greeting = await stub.sayHello();

    	return new Response(greeting);
    },

} satisfies ExportedHandler<Env>;
from workers import DurableObject, handler, Response
from urllib.parse import urlparse

class MyDurableObject(DurableObject):
    async def say_hello(self):
        result = self.ctx.storage.sql.exec(
            "SELECT 'Hello, World!' as greeting"
        ).one()

        return result.greeting

class Default(WorkerEntrypoint):
    async def fetch(self, request):
        url = urlparse(request.url)
        stub = self.env.MY_DURABLE_OBJECT.getByName(url.path)
        greeting = await stub.say_hello()
        return Response(greeting)

このチュートリアルを終えると、次が完了しています。

  • Durable Object を作成した
  • RPC メソッド を呼び出して Durable Object と通信した
  • Durable Object をグローバルにデプロイした

関連リソース

役に立ちましたか?