#javascript #transactions #async-await #google-cloud-firestore
# #javascript #транзакции #асинхронное ожидание #google-облако-firestore
Вопрос:
Итак, в настоящее время я запускаю несколько сценариев для сброса пользовательских балансов в одном из наших приложений. Я использую firestore для получения всех задач, а затем подсчитываю балансы на основе таковых для каждого из наших пользователей. Звучит просто, не так ли? Это должно быть и его нет. Проблема в том, что транзакции прерываются из-за конфликтов записи в один и тот же документ. Это происходит потому, что все задачи передаются транзакции одновременно.
Я пытался использовать метод forEach, который вызывает их прерывание, потому что он продолжает пытаться каждый раз обновлять одну и ту же запись пользователя. И я попытался (пусть task of tasks), который выдает мне ошибку «не удается выполнить задачи».
async function updatestuff(){
console.log("start");
const tasksRef = db.collection('tasks');
try {
const allTasksSnapShot = await tasksRef.get();
allTasksSnapShot.forEach(async(doc) => {
//Run transaction for calculations for each task here
const tskUser = doc.data().taskUser;
const tuser = db.collection('backupusers').doc(tskUser);
if(doc.data().taskStatus == 'Not Completed'){
console.log('NOT');}
if(doc.data().taskStatus != 'Not Completed'){
console.log('Run transaction here and wait for it to finish?');
await db.runTransaction(async t => {
const userSnapShot = await t.get(tuser);
if (!userSnapShot) {return console.log('not a thing')}
//get new balance calculated
const newBalance = userSnapShot.actualbalance doc.data().taskBalanceAdj;
await t.update(tuser, {actualbalance: newBalance});
})
}});
console.log("end")
}
catch (err) {
console.log('Error getting documents', err);
}
}
В настоящее время конфликты между записями документов приводят к прерыванию транзакций на полпути.
Я был бы очень признателен, если бы кто-нибудь мог помочь мне передать каждую задачу транзакции асинхронным образом, ожидая завершения транзакции, а затем передать следующую задачу. Или другой способ, который даст те же результаты….
Заранее спасибо вам, добрые добрые добрые души!
Комментарии:
1. Вы комбинируете использование async / await с then() и catch() . Это затрудняет понимание того, что делает ваш код, и может даже быть неправильным. Если вы хотите использовать async / await, почему бы не применить его во всем коде для обеспечения согласованности и удобочитаемости?
2. Привет, Даг, веришь или нет, я наблюдал за тобой довольно много дня, и твои фейерверки великолепны! Я обновил свой код, чтобы удалить then catch, однако это заставило меня понять, что мне, возможно, нужно пересмотреть эти видео и несколько других примеров асинхронного ожидания.
3. Итак, в чем именно здесь ошибка?
4. Поэтому, когда я запускаю его, я получаю «Необработанное promiserejectionwarning: Ошибка: 10 ПРЕРВАНО: Срок действия указанной транзакции истек или она больше не действительна «. примерно через минуту функция останавливается. Многие транзакции завершаются без проблем в течение первых 30 секунд. Наконец, я получаю сообщение об ошибке в этих записях слишком много разногласий, пожалуйста, попробуйте еще раз, и функция прервется. Поэтому я думаю, что проблема связана с тем, что задачи передаются транзакции синхронно, и при нескольких записях в один и тот же документ транзакция прерывается.
Ответ №1:
Ваша updatestuff
функция запускает столько асинхронных элементов работы, но не возвращает обещание, которое становится разрешенным, когда все они завершены. Вы бы использовали это обещание в своей основной триггерной функции, чтобы сообщить облачным функциям, что вся работа завершена и можно безопасно все очистить. Если вы этого не сделаете, ваша функция рискует быть закрытой до завершения работы.
Имейте в виду, что использование async / await с forEach на самом деле не очень хорошая идея. Функция forEach не будет ждать завершения асинхронной работы, прежде чем перейти к следующему элементу. Это закончится с большим количеством транзакций в полете, и нет способа узнать, когда все они будут выполнены. Вместо этого вы можете не захотеть использовать async / await и вместо этого поместить все обещания транзакции в массив, а затем использовать Promise.all() в этом массиве для создания нового обещания, которое разрешается, когда вся работа завершена. Верните это из своей функции, затем используйте это в своей основной триггерной функции.