$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

英会話LINE BotのCloudflare Queues利用部分をwaitUntil APIで書き直す

OpenAI APIで英会話LINE Botを作る with Hono + Cloudflare Workers + Queues + D1 - $shibayu36->blog; を書いたら、id:mechairoi さんからwaitUntilが使えるんではと教えてもらった。確かにwaitUntilで書き直せればQueues依存がなくせるため、コンポーネントの複雑度もコストも抑えられる。

実際にやってみるとかなり簡単にできたのでメモしておく。

waitUntil APIとは

https://developers.cloudflare.com/workers/runtime-apis/fetch-event/#waituntil

The waitUntil command extends the lifetime of the "fetch" event. It accepts a Promise-based task which the Workers runtime will execute before the handler terminates but without blocking the response. For example, this is ideal for caching responses or handling logging.

waitUntil APIを使えば、ひとまずレスポンスは返した上で、引き続きタスクを実行することができる。

waitUntilの具体的な使い方は Use waitUntil to perform work after Cloudflare Worker returns response | egghead.io の記事も参考になる。

Queuesを使った処理をwaitUntilで置き換える

waitUntilを使えばQueuesを使わずにLINEの1秒制約を回避できる。

  • LINEからリクエストが来たときは、context.waitUntilに重いasync functionを渡し、即座にレスポンスを返す
  • レスポンス返却後もCloudflare Workersは処理を続け、LINEにreplyする

これを実現したのが https://github.com/shibayu36/english-line-bot/pull/1/files のPRだ。

https://github.com/shibayu36/english-line-bot/pull/1/files#diff-a2a171449d862fe29692ce031981047d7ab755ae7f84c707aef80701b3ea0c80R48-R61 のようにasync functionを定義し

async function replyGeneratedMessage(env: Bindings, text: string, replyToken: string) {
  try {
    const generatedMessage = await generateMessageAndSaveHistory(text, env);
    console.log(generatedMessage);

    // Reply to the user
    const lineClient = new Line(env.CHANNEL_ACCESS_TOKEN);
    await lineClient.replyMessage(generatedMessage, replyToken);
  } catch (err: unknown) {
    if (err instanceof Error) console.error(err);
    const lineClient = new Line(env.CHANNEL_ACCESS_TOKEN);
    await lineClient.replyMessage("I am not feeling well right now.", replyToken);
  }
}

Honoを使っているとCloudflare Workersのcontextをc.executionCtxで取れるので、このように書く。 https://github.com/shibayu36/english-line-bot/pull/1/files#diff-a2a171449d862fe29692ce031981047d7ab755ae7f84c707aef80701b3ea0c80R37-R39

  c.executionCtx.waitUntil(replyGeneratedMessage(c.env, text, replyToken));

  return c.json({ message: "ok" });

こうするだけで、即座にレスポンスを返しつつCloudflare Workersで処理を続け、OpenAI APIの呼び出しなど重い処理が行える。便利。

まとめ

今回はwaitUntil APIを使うことで、Cloudflare Queuesへの依存を減らした。単純なAPIではQueuesを使わずとも十分に実現できるAPIが提供されていて、非常にありがたい。よりCloudflare Workersの使いやすさが際立った印象だった。