TiDB + Prisma (Edge Functions Preview)をCloudflare Workersで動かす

2024/03/09に公開

PlanetScaleからTiDB Serverlessへ

サーバーレスデータベースのリーダー的存在だったPlanetScaleが無料プランを廃止することが発表されました。

https://planetscale.com/blog/planetscale-forever

自分はPlanetScaleがまだベータ版だった2021/11からサービスを触り始め、自社サービスのプロダクションデータベースとしても使っており、純粋にファンだったのもあって非常に残念でした。

とはいえ趣味で運用しているサービスのために課金することは難しいため、無料プランがある移転先を探していました。

以下のスクラップはその際に候補となるサービスをリストアップしたメモです。

https://zenn.dev/futa/scraps/49443a5ac66f1e

Supabase、Neon、Vercel Postgres(中身はNeon)、Cloudflare D1は使ったことがあったのですが、TiDB Serverlessは名前を聞いたことがあっただけで、実際に使用したことはありませんでした。

PlanetScaleからの移行先としてMySQL互換のTiDB Serverlessは第一候補になり得るということで調べ始めたのですが、価格も安く、先進的なサービスでした。

移行については、以下のTiDBを開発しているPingCAP社の方のブログを参考にしてください。

https://qiita.com/bohnen/items/de7557078f64891763ac

TiDBとEdge Worker

PlanetScaleやNeonのいいところとして、Cloudflare WorkersやVercelなどフロントエンド文脈の先進的なサービスとの連携があります。

PlanetScaleもNeonもTCP Socketが使えない環境向けにライブラリを提供しており、Fetch APIベースでデータベースに接続できます。

TiDBも同様のライブラリとして @tidbcloud/serverless を提供しており、ORMを使用しない生SQLの形であればすぐにでもCloudflare WorkersなどのEdge Workerで使用することができます。

PrismaとEdge Worker

TypeScriptのORMとしてデファクトスタンダートになっているPrismaですが、Edge Workerではそのまま使用できないことがデメリットのひとつとして知られています。

Prismaが推奨する解決策としてPrisma Accelerate(旧:Prisma Data Proxy)というマネージドサービスのコネクションプールを経由する方法がありますが、レイテンシやコストの課題が残ります。

Cloudflare WorkersでTCP Socketが使えるようになった際には、そのままPrismaが動くのではと期待したのですが、結果的には動きませんでした。

詳細な理由については以下のツイートを参照してください。

https://twitter.com/ogawa0071/status/1658788985307807746

このツイートから1年弱が経ち、PrismaがEdge Functions Early Accessというものを始めておりPrisma v5.11.0がEdge Functionsへのプレビュー対応を始めており、遂にEdge Workerから直接Prismaが利用できるようになってきました。

https://www.prisma.io/blog/prisma-orm-support-for-edge-functions-is-now-in-preview

現在実装されている対応先データベースは以下です。

  • PlanetScale
  • Neon
  • libSQL(Turso)
  • PostgreSQL(TCP Socket)

TiDBとPrisma Edge Functions Preview

先ほどのリストにTiDBは含まれていませんが、Prismaの仕様に沿ってTiDB側が @tidbcloud/prisma-adapter を実装しており、ドキュメントにも記載されています。

https://docs.pingcap.com/tidbcloud/serverless-driver-prisma-example

このライブラリを利用することでPrismaからTiDBにFetch APIベースで通信することが可能となります。

しかしながら、ドキュメントにはCloudflare WorkersとVercel Edge Functions(中身はCloudflare Workers)ではまだ動作しないと書かれていました。

とはいえPrisma側でEdge Functions Previewが始まっていることも加味すると、じつは動作するのではと考え試してみたところ、無事動作確認ができました!

ソースコード

TiDB + Prisma + Cloudflare Workersの特徴的なコードだけ以下に引用します。
全体のソースコードはGitHubを参考にしてください。

npm install -D prisma
npm install @prisma/client @tidbcloud/prisma-adapter @tidbcloud/serverless
prisma/schema.prisma
generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["driverAdapters"]
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}
src/index.ts
import { connect } from "@tidbcloud/serverless";
import { PrismaTiDBCloud } from "@tidbcloud/prisma-adapter";
import { PrismaClient } from "@prisma/client";

interface Env {
  DATABASE_URL: string;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const connection = connect({ url: env.DATABASE_URL });
    const adapter = new PrismaTiDBCloud(connection);
    const prisma = new PrismaClient({ adapter });

    const users = await prisma.user.findMany();
    const result = JSON.stringify(users);
    return new Response(result);
  },
};
wrangler.toml
node_compat = true

デモ

https://tidb-prisma-cloudflare.ogawa0071.workers.dev/

全体のソースコード

https://github.com/ogawa0071/tidb-prisma-cloudflare

まとめ

PlanetScaleが無料プランを廃止してしまいましたが、TiDB Serverlessがほぼ互換の機能を無料で提供しており、Edge Worker上のPrismaから直接続できました。

私は今後、MySQLが必要なサービスの実装にはTiDB Serverlessを活用していこうと思っています。

Discussion