Cloudflare上でトランザクションが成功している(ように見える)のに、DBに反映されていない現象に遭遇した
Cloudflareで動作する、個人開発プロジェクトで、次のような問題に遭遇しました。
手元マシンの開発環境でnpm run devで実行し、ブラウザでアクセスしているときは、バックエンド処理でDBトランザクションが行われて成功し、(当然)DBも更新されるのに、いざCloudflare同じ処理を動かすと、DBトランザクションが成功している(ように見える)のに、DBが更新されていない。
まず、Cloudflareの実行時間制限にかかっているのか、と疑いましたが、エラーも全く起きていないので、これが原因ではなさそうでした。
アプリケーション上で他の箇所でもトランザクションを使っているところがあり、それらはCloudflareとローカル開発環境で動作の違いは無いのに、ある特定のリクエストだけ現象が起きていました。
ざっくりと、以下のような処理です。
const deleteById = async (db: TiDBServerlessDatabase<typeof schema>, form: FormData) => {
const id = form.get('id')
try {
db.transaction(async (tx) => {
await tx.delete(TableA).where(eq(TableA.id, id))
await tx.delete(TableB).where(eq(TableB.id, id))
})
} catch (e) {
return { status: 'fail', msg: e }
}
return { status: 'success', msg: '削除しました' }
}
Remixのactionとして動作しており、returnが行われると、HTTP応答がブラウザに帰ります。
上記コードの問題は何でしょうか???? 正解は↓
const deleteById = async (db: TiDBServerlessDatabase<typeof schema>, form: FormData) => {
const id = form.get('id')
try {
await db.transaction(async (tx) => {
await tx.delete(TableA).where(eq(TableA.id, id))
await tx.delete(TableB).where(eq(TableB.id, id))
})
} catch (e) {
return { status: 'fail', msg: e }
}
return { status: 'success', msg: '削除しました' }
}
db.transactionの前にawaitが抜けていました。それで、実際の動作順としてはreturnでHTTP応答が行われた後にトランザクションが動作していたようです。Cloudflareだと、HTTPリクエストが完了すると、直ちにworkerのインスタンスが破棄されるようで、トランザクションが終わるところまで処理が行われていなかったと思われます。手元のNode.jsだと当然そういうこともないので、awaitが抜けていてもトランザクションが完了し、DBが更新されていたわけです。