简体   繁体   中英

Why is this Firestore Transaction freezing?

The simple code below is freezing.

To reproduce, just replace this.firestoreProvider with admin.initializeApp().firestore()

   console.log('Init the cat')
        const kittyRef = this.firestoreProvider
            .fs
            .collection('cats')
            .doc('kitty')
        await kittyRef.set({
            name: 'Kitty',
            age: 85,
            feedCount: 0,
        })
        console.log('Feeding the cat')
        await this.firestoreProvider.fs.runTransaction(async transaction => {
            const snapshot = await transaction.get(kittyRef);
            const cat = snapshot.data()
            if(cat.isDead) return
            if(cat.age > 84) {
                cat.isDead = true
                await kittyRef.set(cat); // this need be written to the db
                throw new Error('Kitty is dead')
            }
            cat.feeCount ++
            await transaction.set(kittyRef, cat)
        }, {maxAttempts: 5})
        console.log('success')

I also discovered that once you run this code, it freezes but it also freezes every client that tries to read the kittyRef for about 1 minutes.

It is not entirely clear what you are trying to do, but you have at least 2 problems:

  1. You shouldn't be directly calling set() on kittyRef inside the transaction -- you've locked the object by reading it inside that transaction. You need to do that with a transaction.set() call. This is why you are getting a hang.

  2. Throwing an (unhandled) exception inside the transaction is going to cause it to abort as it will cause the updateFunction to return a failed promise). More documentation here . The best answer here would be to pass information out of the transaction function and handle it once the transaction is over.

So, this code will run and complete and leave the cat marked as dead, but it won't throw the error. It should be enough to get you started though:

console.log('Init the cat')
const kittyRef = admin.firestore()
    .collection('cats')
    .doc('kitty')
await kittyRef.set({
      name: 'Kitty',
      age: 85,
      feedCount: 0,
})
console.log('Feeding the cat')
await admin.firestore().runTransaction(async transaction => {
      const snapshot = await transaction.get(kittyRef);
      const cat = snapshot.data()
      if(cat.isDead) return
      if(cat.age > 84) {
            cat.isDead = true
            await transaction.set(kittyRef, cat); // this need be written to the db
            console.log('kitty now dead');
            return;
      }
      cat.feeCount ++
      await transaction.set(kittyRef, cat)
}, {maxAttempts: 5})
console.log('success')

Also, I note it appears you have a typo of feeCount instead of feedCount , but that is not related to your current question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM