Hono Service bindings入門
Cloudflare WorkersのService Bindings機能を使って、パブリックにアクセス可能なURLを経由せずに別のWorkersを呼び出す方法を解説します。Honoを使った複数Workersの連携実装例を紹介します。
目次
はじめに
Cloudflare Workers にはパブリックにアクセス可能な URL を経由せず別の Workers を呼び出すことができます。
今回は Cloudflare Network 内で通信できる Service Bindings の機能を使って、複数の Workers を連携したいと思います。
内容としてはクライアントからのエンドポイントを想定した Webhook という名前のエンドポイントを Hono で作成し、エンドポイントごとに別の Workers を呼び出す構成です。
記事の作成にはこちらの投稿を参考にさせていただきました。
Honoを使ってCloudflare Multi Workers環境を作る
この記事の対象者
Hono で別の Workers を連携したい人
成果物
GitHub - Suntory-Y-Water/hono-service-binding: Hono にCloudflare WorkersのService Bindingsを使った練習用リポジトリ
Hono にCloudflare WorkersのService Bindingsを使った練習用リポジトリ - Suntory-Y-Water/hono-service-binding
Monorepo環境を構築
参考にさせていただいた記事と同じ構成のほうが、誤ったときに原因をつきとめやすいので同じ構成にさせていただきます。
複数の Cloudflare Workers を 1 つのリポジトリで管理するために、Monorepo を作成し、turborepo で環境構築します。
パッケージ共通のツールはプロジェクトルートにインストールしておきます。
{
"devDependencies": {
"turbo": "^1.10.9",
"wrangler": "^3.1.2"
},
"scripts": {
"dev": "turbo dev"
}
}pnpm run dev でパッケージを平行に起動するために、turborepo を設定します。
{
"$schema": "https://turbo.build/schema.json",
"pipeline": {
"dev": {
"dependsOn": ["^dev"]
}
}
}Workers のコードは、workers ディレクトリにパッケージとして配置します。
packages:
- "workers/*"node_modules
.wrangler
.turbowebhook アプリを作成
クライアントからのリクエストを想定した webhook アプリを作成します。
他の内部プライベートサービスと通信する役割を担っています。
cd workers/
create hono@latestService Bindingの設定を行う
webhookのService Binding設定
Service Binding を設定するために、webhook の wrangler.toml に services フィールドを追加します。
名前はなんでもいいですが、分かりやすく HTTP_SERVICE と RPC_SERVICE に設定します。
compatibility_date は 2024-07-01 に設定します。
name = "webhook"
compatibility_date = "2024-07-01"
services = [
{ binding = "HTTP_SERVICE", service = "http-service" },
{ binding = "RPC_SERVICE", service = "rpc-service" },
]rpc-serviceのService Binding設定
Cloudflare Workers の Service Binding には RPC と HTTP の 2 通りあります。
RPC の場合、別の worker を JavaScript の関数のように使用できます。
workers ディレクトリに到達したら、pnpm create cloudflare@latest rpc-service で rpc で使用する worker を作成していきます。
rpc-service が作成できたら、wrangler.toml の内容を編集していきます。
name = "rpc-service"
main = "src/index.ts"
compatibility_date = "2024-07-01"
[dev]
port = 8888ポート番号は初期設定の 8787 以外であれば被らなそうなものにしましょう
http-serviceのService Binding設定
http-service は Hono で作成します。pnpm create hono@latest で作成後、wrangler.toml の内容を編集していきます。
name = "http-service"
compatibility_date = "2024-07-01"
[dev]
port = 9999ロジックの作成
各 worker のロジックを書いていきます。どの worker が動いているか分かれば良いので、内容は適当です。
http-service ではテキストをレスポンスします。
import { Hono } from "hono";
const app = new Hono().basePath("/http");
app.get("/", (c) => c.text("Hello Http Service Worker!"));
export default app;rpc-service では Service Binding を介して、同じ Cloudflare アカウント上の他の worker から呼び出すことができる method を実装します。
Remote-procedure call (RPC)
The built-in, JavaScript-native RPC system built into Workers and Durable Objects.
WorkerEntrypoint を継承した RpcService を Export します。
import { WorkerEntrypoint } from "cloudflare:workers";
export class RpcService extends WorkerEntrypoint {
async fetch(request: Request): Promise<Response> {
return new Response("Hello Rpc Service Worker!");
}
add(a: number, b: number): number {
return a + b;
}
}
export default RpcService;webhook/src/index.ts で Export した Service Binding を型安全に使用します。
Cloudflare Workers - Hono
Web framework built on Web Standards for Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, Node.js, and others. Fast, but not only fast.
Bindings という型を定義して、Hono の Generics に渡します。
このとき、Bindings のキーは wrangler.toml の services フィールドに設定した binding の値と同じにしておきます。
import { Hono } from "hono";
import type { RpcService } from "../../rpc-service/src";
type Bindings = {
// RPCの場合、Service<T>で使用する必要があります。
RPC_SERVICE: Service<RpcService>;
HTTP_SERVICE: Fetcher;
};
const app = new Hono<{ Bindings: Bindings }>();
app.get("/", (c) => {
return c.text("Hello Hono!");
});
app.get("/rpc", async (c) => {
// 呼び出し元が非同期関数ではなくても非同期扱いになる。
const res = await c.env.RPC_SERVICE.add(1, 2);
return c.text(`add result: ${res}`);
});
app.get("/http", async (c) => {
const res = await c.env.HTTP_SERVICE.fetch(c.req.raw);
const text = await res.text();
return c.text(text);
});
export default app;
注意点を上げるとすれば、以下 2 つです。
- RPC で呼び出すメソッドが非同期関数ではなくても、非同期扱いになります。
- type Bindings で RPC を型安全に使用するときは、
Service<T>で使用する必要があります。
Remote-procedure call (RPC)
The built-in, JavaScript-native RPC system built into Workers and Durable Objects.
デプロイする
各 worker を pnpm run deploy します。
デプロイ後、https://webhook.ドメイン名.workers.dev/http にアクセスすれば「Hello Http Service Worker!」と表示されます。
https://webhook.ドメイン名.workers.dev/rpc にアクセスすれば、「add result: 3」と表示され、正常に呼び出されていることが確認できると思います。
実運用のするときは参考にさせていただいた記事のようなトークンの検証などを設けたほうが良いですね。
おわりに
いかがでしたでしょうか。
既にこのテーマで記事を書いている人や、公式ドキュメントが丁寧に書かれているのもあり開発体験がとても良かったです。
次作成するアプリの規模によりますが取り入れてみたいですね!
以上になります!
参考
Honoを使ってCloudflare Multi Workers環境を作る
LINE Botの開発でCloudflareとHonoを使う理由
Service bindings
Facilitate Worker-to-Worker communication.
GitHub - cloudflare/js-rpc-and-entrypoints-demo
Contribute to cloudflare/js-rpc-and-entrypoints-demo development by creating an account on GitHub.