本文へ移動

Cloudflare Durable Objects ​

Cloudflare Durable Objects は HTTP リクエストを直接処理できません。代わりに、次の 2 段階の仕組みで動作します。

  1. Worker がクライアントからの HTTP fetch リクエストを受け取ります
  2. Worker が Durable Object に RPC(リモートプロシージャコール)を行います
  3. Durable Object が RPC を処理し、結果を Worker に返します
  4. Worker が HTTP レスポンスをクライアントに返します

Cloudflare Worker で Hono をルーターとして使い、RPC(リモートプロシージャコール)を通じて Durable Objects とやり取りできます。Cloudflare Workers の互換性日付 2024-04-03 以降では、この方法が推奨されています。

例:カウンターの Durable Object ​

ts
import { DurableObject } from 'cloudflare:workers'
import { Hono } from 'hono'

export class Counter extends DurableObject {
  // In-memory state
  value = 0

  constructor(ctx: DurableObjectState, env: unknown) {
    super(ctx, env)

    // `blockConcurrencyWhile()` ensures no requests are delivered until initialization completes.
    ctx.blockConcurrencyWhile(async () => {
      // After initialization, future reads do not need to access storage.
      this.value = (await ctx.storage.get('value')) || 0
    })
  }

  async getCounterValue() {
    return this.value
  }

  async increment(amount = 1): Promise<number> {
    this.value += amount
    await this.ctx.storage.put('value', this.value)
    return this.value
  }

  async decrement(amount = 1): Promise<number> {
    this.value -= amount
    await this.ctx.storage.put('value', this.value)
    return this.value
  }
}

// Create a new Hono app to handle incoming HTTP requests
type Bindings = {
  COUNTER: DurableObjectNamespace<Counter>
}

const app = new Hono<{ Bindings: Bindings }>()

// Add routes to interact with the Durable Object
app.get('/counter', async (c) => {
  const env = c.env
  const id = env.COUNTER.idFromName('counter')
  const stub = env.COUNTER.get(id)
  const counterValue = await stub.getCounterValue()
  return c.text(counterValue.toString())
})

app.post('/counter/increment', async (c) => {
  const env = c.env
  const id = env.COUNTER.idFromName('counter')
  const stub = env.COUNTER.get(id)
  const value = await stub.increment()
  return c.text(value.toString())
})

app.post('/counter/decrement', async (c) => {
  const env = c.env
  const id = env.COUNTER.idFromName('counter')
  const stub = env.COUNTER.get(id)
  const value = await stub.decrement()
  return c.text(value.toString())
})

// Export the Hono app as the Worker's fetch handler
export default app

wrangler.jsonc:

jsonc
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "durable",
  "main": "src/index.ts",
  "compatibility_date": "2025-04-14",
  "migrations": [
    {
      "new_sqlite_classes": ["Counter"],
      "tag": "v1",
    },
  ],
  "durable_objects": {
    "bindings": [
      {
        "class_name": "Counter",
        "name": "COUNTER",
      },
    ],
  },
  "observability": {
    "enabled": true,
  },
}

これで、Durable Object と連携する Hono アプリケーションが完成しました。Hono ルーターは、Durable Object のメソッドを呼び出して公開するための、わかりやすい API インターフェースを提供します。

MIT ライセンスで公開されています。