1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Firebase Functions】トランザクション処理を実装したのでまとめました

Last updated at Posted at 2021-07-08

概要

業務で使用していたfirebase functionsをトランザクション処理に修正するようになったのでざっくりと内容をまとめた
公式ドキュメント

トランザクション処理(transaction)とは

以下のような特徴があります。

  • 複数の処理を一括で行う
  • 常に最新のデータに対して処理を行う
  • 全ての処理が成功することが保証されてから処理を行う
    • どれか一つの処理が失敗した場合、他の全ての処理も実行されない

複数の処理を一括で行う

以下のようなトランザクション処理ではref1ref2の更新が同時に実行され、それぞれのtimeは必ずイコールになる

db.runTransaction((transaction) => {
    const ref1 = db.collection('sample').doc('1')
    const ref2 = db.collection('sample').doc('2')
    transaction.update(ref1, {
        time: firebase.firestore.FieldValue.serverTimestamp()
    })
    transaction.update(ref2, {
        time: firebase.firestore.FieldValue.serverTimestamp()
    })
    return
})

常に最新のデータに対して処理を行う

トランザクション処理を実行中に他の処理でデータが更新された場合、再度トランザクション処理を実行する

例えば、以下のような流れのトランザクション処理があった時

  1. ref1のデータを読み取る
  2. ref2のデータに読み取ったref1のデータをコピーする
db.runTransaction(async (transaction) => {
    const ref1 = db.collection('sample').doc('1')
    const ref2 = db.collection('sample').doc('2')
    const doc = await transaction.get(ref1)
    
    // このタイミングで読み取ったデータが外部の処理で更新される
    
    transaction.update(ref2, doc.data())
    return Promise.resolve()
})

1と2の処理の間にref1のデータが更新された場合、再度ref1を読み取る
つまり上記のトランザクション処理は以下のような流れになる

  1. ref1のデータを読み取る
  2. 外部の処理でref1が更新される
  3. 再度ref1のデータを読み取る ← 更新後の最新のデータを取得している
  4. ref2のデータに読み取ったref1のデータをコピーする

全ての処理が成功することが保証されてから処理を行う

firestoreのルールでref2に対しての書き込み処理が禁止されているなど、何かしらの要因でref2の更新が失敗した場合、ref1の更新も実行されない

db.runTransaction((transaction) => {
    const ref1 = db.collection('sample').doc('1')
    const ref2 = db.collection('sample').doc('2')
    transaction.update(ref1, {
        time: firebase.firestore.FieldValue.serverTimestamp()
    })
    // この処理が失敗するとき、`ref1`の更新も実行されない
    transaction.update(ref2, {
        time: firebase.firestore.FieldValue.serverTimestamp()
    })
    return
})

まとめ

いくつかメリットはありますが、特に「常に最新のデータに対して処理を行う」の恩恵が大きいと感じました。
funcitonsはトリガーごとにそれぞれ非同期で実行されるので、通常のドキュメント操作の処理ではデータの整合性を取るのが難しいですがトランザクション処理を実装することで解決できました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?