1
0

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.

[Firestore]transactionで悲観ロックできない

1
Posted at

複数の処理が連続して行われる場合にtransactionの排他制御を用いることは多くあると思います。
今回firestoreのtransaction中で悲観ロックを用いたのですがなぜかうまくいかない事象(分離レベル勘違いしていただけ)が起きたので解決法をまとめます。

firebaseのトランザクションの使い方

問題

簡潔に言うと次の処理をしていた。

  1. tokenを取得
  2. apiを叩く(token)
  3. tokenが更新されるので保存
admin.firestore().runTransaction(async (transaction) => {
  const token = await transaction.get(...)
  const res = await postApi(token)
  transaction.set(res.token)
})

ここでtransaction A,Bが連続して実行された時、transaction.getの時点でロックされ、transactionの終了まで待機する想定であった。

1. [A] 開始
1. [B] 開始
1. [A] get
1. [B] getを待機
1. [A] postApi
1. [A] 終了
1. [B] get完了
1. [B] postApi
1. [B] 終了

実際は以下のようになりロックできていなかった?

1. [A] 開始
1. [B] 開始
1. [A] get
1. [B] get
1. [A] postApi
1. [B] postApi
1. [B] エラー
1. [A] 終了

解決法

普通にtransaction自体は正しく動いていたので任意の回数retryさせた。

admin.firestore().runTransaction(async (transaction) => {
  const token = await transaction.get(...)
  const res = (await postApi(token)).catch((e) => 再度実行)
  transaction.set(res.token)
})

原因としては分離レベルの理解が甘かった。
firestoreの分離レベルが"READ COMMITTED"であり、更新を検知した時に再度getするみたい。
🔽詳細

1
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?