コンテンツにスキップ

RPC (WorkerEntrypoint)

サービスバインディングを使用すると、1つのWorkerが別のWorkerを呼び出すことができ、公開アクセス可能なURLを介さずに行うことができます。

サービスバインディングを使用して、あなたのWorkerが他のWorkersに提供する独自の内部APIを作成できます。これは、組み込みのWorkerEntrypointクラスを拡張し、独自の公開メソッドを追加することで実現できます。これらの公開メソッドは、あなたのCloudflareアカウント内の他のWorkersによって直接呼び出すことができ、これらのWorkersはこのWorkerに対してバインディングを宣言します。

WorkersのRPCシステムは、同じWorker内でJavaScript関数を呼び出すのとできるだけ似た感覚で設計されています。ほとんどの場合、すべてが単一のWorker内にあるかのようにコードを書くことができるはずです。

例えば、次のWorkerは公開メソッドadd(a, b)を実装しています:

For example, if Worker B implements the public method add(a, b):

name = "worker_b"
main = "./src/workerB.js"
import { WorkerEntrypoint } from "cloudflare:workers";
export default class extends WorkerEntrypoint {
async fetch() { return new Response("Hello from Worker B"); }
add(a, b) { return a + b; }
}

Worker A can declare a binding to Worker B:

name = "worker_a"
main = "./src/workerA.js"
services = [
{ binding = "WORKER_B", service = "worker_b" }
]

Making it possible for Worker A to call the add() method from Worker B:

export default {
async fetch(request, env) {
const result = await env.WORKER_B.add(1, 2);
return new Response(result);
}
}

RPCシステムを使用するために特別なプロトコルを学んだり、実装したり、考えたりする必要はありません。この場合、クライアントであるWorker AはWorker Bを呼び出し、クライアントが提供する特定の引数を使用して特定の手続きを実行するように指示します。これは、標準のJavaScriptクラスを使用して実現されます。

WorkerEntrypointクラス

WorkerからRPCメソッドを提供するには、以下の例のようにWorkerEntrypointクラスを拡張する必要があります:

import { WorkerEntrypoint } from "cloudflare:workers";
export default class extends WorkerEntrypoint {
async add(a, b) { return a + b; }
}

Workerが呼び出されるたびに、このクラスの新しいインスタンスが作成されます。Workerはクラスとして実装されていますが、状態を持たないことに注意してください — クラスインスタンスは呼び出しの期間のみ存在します。Workers内で状態を永続化または調整する必要がある場合は、Durable Objectsを使用する必要があります。

バインディング (env)

envオブジェクトは、WorkerEntrypointクラスのクラスプロパティとして公開されています。

例えば、環境変数 GREETINGにバインディングを宣言するWorker:

name = "my-worker"
[vars]
GREETING = "Hello"

は、this.env.GREETINGを呼び出すことでアクセスできます:

import { WorkerEntrypoint } from "cloudflare:workers";
export default class extends WorkerEntrypoint {
fetch() { return new Response("Hello from my-worker"); }
async greet(name) {
return this.env.GREETING + name;
}
}

この方法で任意のタイプのバインディングを使用できます。

ライフサイクルメソッド (ctx)

ctxオブジェクトは、WorkerEntrypointクラスのクラスプロパティとして公開されています。

例えば、waitUntil()メソッドを呼び出すことで呼び出しコンテキストの寿命を延ばすことができます:

import { WorkerEntrypoint } from "cloudflare:workers";
export default class extends WorkerEntrypoint {
fetch() { return new Response("Hello from my-worker"); }
async signup(email, name) {
// sendEvent()は、このメソッドが呼び出し元に値を返した後も実行を続けます
this.ctx.waitUntil(this.#sendEvent("signup", email))
// 他の作業を実行
return "Success";
}
async #sendEvent(eventName, email) {
//...
}
}

名前付きエントリポイント

デフォルトのエクスポートに加えて、単一のWorker内から任意の数の名前付きWorkerEntrypointクラスをエクスポートすることもできます。これにより、特定の名前付きエントリポイントにサービスバインディングを宣言できます。

これを使用して、複数の計算をグループ化できます。例えば、アプリケーション内の各権限ロールに対して異なるWorkerEntrypointを作成し、これらを使用してロール固有のRPCメソッドを提供することができます:

name = "todo-app"
[[d1_databases]]
binding = "D1"
database_name = "todo-app-db"
database_id = "<unique-ID-for-your-database>"
import { WorkerEntrypoint } from "cloudflare:workers";
export class AdminEntrypoint extends WorkerEntrypoint {
async createUser(username) {
await this.env.D1.prepare("INSERT INTO users (username) VALUES (?)")
.bind(username)
.run();
}
async deleteUser(username) {
await this.env.D1.prepare("DELETE FROM users WHERE username = ?")
.bind(username)
.run();
}
}
export class UserEntrypoint extends WorkerEntrypoint {
async getTasks(userId) {
return await this.env.D1.prepare(
"SELECT title FROM tasks WHERE user_id = ?"
)
.bind(userId)
.all();
}
async createTask(userId, title) {
await this.env.D1.prepare(
"INSERT INTO tasks (user_id, title) VALUES (?, ?)"
)
.bind(userId, title)
.run();
}
}
export default class extends WorkerEntrypoint {
async fetch(request, env) {
return new Response("Hello from my to do app");
}
}

次に、別のWorkerでAdminEntrypointに直接サービスバインディングを宣言できます:

name = "admin-app"
[[services]]
binding = "ADMIN"
service = "todo-app"
entrypoint = "AdminEntrypoint"
export default {
async fetch(request, env) {
await env.ADMIN.createUser("aNewUser");
return new Response("Hello from admin app");
},
};

D1の設定方法については、D1ドキュメントで詳しく学ぶことができます。

このTo Doアプリの完全な例や、名前付きエントリポイントを使用して構築されたDiscordボットを試すには、GitHubからcloudflare/js-rpc-and-entrypoints-demoリポジトリをクローンしてください。

さらなる学び