Почему эта транзакция Firestore зависает? - PullRequest
1 голос
/ 04 августа 2020

Приведенный ниже простой код зависает.

Для воспроизведения просто замените this.firestoreProvider на 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')

Я также обнаружил, что после запуска этого кода он зависает, но он также замораживает каждого клиента, который пытается прочитать kittyRef примерно на 1 минуту.

1 Ответ

2 голосов
/ 04 августа 2020

Не совсем понятно, что вы пытаетесь сделать, но у вас как минимум 2 проблемы:

  1. Вы не должны напрямую звонить set() на kittyRef внутри транзакция - вы заблокировали объект, прочитав его внутри этой транзакции. Это нужно сделать с помощью вызова transaction.set(). Вот почему вы получаете зависание.

  2. Вызов (необработанного) исключения внутри транзакции приводит к , вызывая прерывание , так как это вызовет updateFunction чтобы вернуть невыполненное обещание). Дополнительная документация здесь . Лучшим ответом здесь было бы передать информацию из функции транзакции и обработать ее после завершения транзакции.

Итак, этот код будет запущен, завершен и оставьте кошку помеченной как мертвую, но это не приведет к ошибке. Однако этого должно быть достаточно, чтобы вы начали:

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')

Кроме того, я отмечаю, что у вас есть опечатка feeCount вместо feedCount, но это не связано с вашим текущим вопросом.

...