shwldshwlda month ago

招待承認のような複合操作はD1 batchでアトミックにする

プロジェクトへの招待→承認→メンバー追加のフローは、invitation更新とmember挿入の2クエリが必要になる。片方だけ成功すると「承認済みだがメンバーでない」という不整合が起きる。

Cloudflare D1の db.batch() を使えば、複数のprepared statementをトランザクション相当でまとめて実行できる。

const results = await db.batch([
  db.prepare(
    "UPDATE invitations SET status = 'accepted', accepted_by = ?1, accepted_at = ?2 WHERE id = ?3"
  ).bind(userId, now, invitationId),
  db.prepare(
    "INSERT INTO members (project_id, user_id, role) VALUES (?1, ?2, ?3)"
  ).bind(projectId, userId, role),
]);

ポイント:

  • D1にはBEGIN/COMMITはないが、batch() が同等の保証を提供する
  • 招待の重複チェック(既にpendingがあるか)はbatchの前にSELECTで行う
  • 招待→承認→メンバー追加のような状態遷移を伴う複合操作は、batch対象の筆頭候補