TiDB + Prisma (Edge Functions Preview)をCloudflare Workersで動かす
PlanetScaleからTiDB Serverlessへ
サーバーレスデータベースのリーダー的存在だったPlanetScaleが無料プランを廃止することが発表されました。
自分はPlanetScaleがまだベータ版だった2021/11からサービスを触り始め、自社サービスのプロダクションデータベースとしても使っており、純粋にファンだったのもあって非常に残念でした。
とはいえ趣味で運用しているサービスのために課金することは難しいため、無料プランがある移転先を探していました。
以下のスクラップはその際に候補となるサービスをリストアップしたメモです。
Supabase、Neon、Vercel Postgres(中身はNeon)、Cloudflare D1は使ったことがあったのですが、TiDB Serverlessは名前を聞いたことがあっただけで、実際に使用したことはありませんでした。
PlanetScaleからの移行先としてMySQL互換のTiDB Serverlessは第一候補になり得るということで調べ始めたのですが、価格も安く、先進的なサービスでした。
移行については、以下のTiDBを開発しているPingCAP社の方のブログを参考にしてください。
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が動くのではと期待したのですが、結果的には動きませんでした。
詳細な理由については以下のツイートを参照してください。
このツイートから1年弱が経ち、PrismaがEdge Functions Early Accessというものを始めておりPrisma v5.11.0がEdge Functionsへのプレビュー対応を始めており、遂にEdge Workerから直接Prismaが利用できるようになってきました。
現在実装されている対応先データベースは以下です。
- PlanetScale
- Neon
- libSQL(Turso)
- PostgreSQL(TCP Socket)
TiDBとPrisma Edge Functions Preview
先ほどのリストにTiDBは含まれていませんが、Prismaの仕様に沿ってTiDB側が @tidbcloud/prisma-adapter
を実装しており、ドキュメントにも記載されています。
このライブラリを利用することで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
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"]
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
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);
},
};
node_compat = true
デモ
全体のソースコード
まとめ
PlanetScaleが無料プランを廃止してしまいましたが、TiDB Serverlessがほぼ互換の機能を無料で提供しており、Edge Worker上のPrismaから直接続できました。
私は今後、MySQLが必要なサービスの実装にはTiDB Serverlessを活用していこうと思っています。
Discussion