简体   繁体   English

为什么 firebase cloud-function javascript promise 运行次数超过循环调用次数?

[英]Why does firebase cloud-function javascript promise run more than the number of loop invocations?

I have a cloud function that is triggered when a sale/purchase is committed into firestore.我有一个云 function,当销售/购买提交到 Firestore 时触发。 This function's purpose is to update the inventory level centrally.此功能的目的是集中更新库存水平。

The function works just fine if I'm updating an item's inventory at only 1 warehouse, but doing so for multiple warehouses has unexpected behavior.如果我只在 1 个仓库更新物品的库存,function 工作得很好,但对多个仓库执行此操作会出现意外行为。 I'm looping through all the warehouses that are affected to calculate the total inventory level changes, and every iteration kicks-off a javascript promise.我遍历所有受影响的仓库以计算总库存水平变化,并且每次迭代都会启动 javascript promise。

The problem seems to occur with the way the promises are invoked.问题似乎与调用承诺的方式有关。 Eg: if I want to update 3 warehouses and loop 3 times, somehow 5 promises are being kicked-off.例如:如果我想更新 3 个仓库并循环 3 次,不知何故 5 个 Promise 正在启动。 This is visible through the logs.这可以通过日志看到。 I've researched similar questions here, but the solutions were suggested while firestore was still in beta and might not be the right way forward.我在这里研究了类似的问题,但是在 firestore 仍处于测试阶段时提出了解决方案,可能不是正确的前进方向。 ( Firestore transactions getting triggered multiple times resulting in wrong data ) Firestore 事务多次触发导致错误数据

Here is the code这是代码

export const onTransactionCreate = functions.firestore
    .document('/companies/{companyId}/sub_transactions/{transId}')
    .onCreate(async (snapshot, context) => {
        const transId = context.params.transId
        
        const stock_transaction: IStockTransaction = <IStockTransaction>snapshot.data()
        const trans_type: TRANS_TYPE = stock_transaction.trans_type

        const promises: any[] = []

        stock_transaction.lineItems.forEach((element, index) => {
            const ITEM_GUID = element.item_guid

            const is_increasing = isIncreasingTransaction(element.line_trans_type)
            const delta_stock = element.qty_transaction * (is_increasing ? 1 : -1)

            const TARGET_BRANCH_ID = element.target_branch_guid
            
            const itemRef = db.collection(FIRESTORE_PATHS.COL_COMPANIES).doc(companyId).
                collection(FIRESTORE_PATHS.SUB_COMPANIES_ITEMS).
                doc("" + ITEM_GUID)

            const item_promise = db.runTransaction(async t => {
                try {
                    const item_doc = await t.get(itemRef)

                    const item_branch_quantities: IBranchQuantity[] = (item_doc.data()!.branch_quantities || new Array())
                    const item_branch_ids: string[] = (item_doc.data()!.available_branch_ids || new Array())

                    const branch_index = item_branch_ids.indexOf(TARGET_BRANCH_ID)
                    console.log(`${transId} Line Item ${index}, after document.get(), search branch index: ${branch_index}`)
                    if (branch_index !== -1) {
                        const prev_qty = item_branch_quantities[branch_index]
                        const updated_qty = prev_qty.quantity + delta_stock
                        item_branch_quantities[branch_index] = {
                            item_guid: prev_qty.item_guid,
                            branch_guid: prev_qty.branch_guid,
                            quantity: updated_qty
                        }
                        console.log(`${transId} Line Item ${index} Updating qty @ item ${delta_stock}, prev qty ${prev_qty.quantity}`)
                    } else {
                        item_branch_ids.push(TARGET_BRANCH_ID)
                        item_branch_quantities.push({
                            item_guid: element.item_guid,
                            branch_guid: TARGET_BRANCH_ID,
                            quantity: delta_stock
                        })
                        console.log(`${transId} Line Item ${index} Adding qty @ item ${delta_stock}`)
                    }
                    
                    t.update(itemRef, {
                        branch_quantities: item_branch_quantities,
                        available_branch_ids: item_branch_ids
                    })
                } catch (err) {
                    throw new Error(err)
                }
            })
            promises.push(item_promise)

        });

        return Promise.all(promises)
    })

当循环有 3 个元素但被调用 5 次时的日志消息

we have found the solution by reading this article.我们通过阅读这篇文章找到了解决方案。

A transaction consists of any number of get() operations followed by any number of write operations such as set(), update(), or delete().一个事务由任意数量的 get() 操作和任意数量的写操作组成,例如 set()、update() 或 delete()。 In the case of a concurrent edit, Cloud Firestore runs the entire transaction again.在并发编辑的情况下,Cloud Firestore 会再次运行整个事务。 For example, if a transaction reads documents and another client modifies any of those documents, Cloud Firestore retries the transaction.例如,如果一个事务读取文档,而另一个客户端修改了这些文档中的任何一个,则 Cloud Firestore 会重试该事务。 This feature ensures that the transaction runs on up-to-date and consistent data.此功能可确保事务在最新且一致的数据上运行。

 lineItems.forEach(element => { const delta_transaction = element.qty * (isLineTransIncrease(element.line_trans_type)? 1: -1) const itemRef = db.collection('companies').doc(companyId).collection('sub_items').doc("" + element.item_guid) const p = db.runTransaction(t => { return t.get(itemRef).then(doc => { let item_branch_quantities: IBranchQuantity[] = doc.data().:branch_quantities let item_branch_ids. string[] = doc.data().:available_branch_ids if (.item_branch_quantities) item_branch_quantities = new Array() if (:item_branch_ids) item_branch_ids = new Array() const branch_index = item_branch_ids.indexOf(current_branch_id) if (branch_index,== -1) { const prev_qty = item_branch_quantities[branch_index] const updated_qty: number = prev_qty.quantity + delta_transaction item_branch_quantities[branch_index] = { item_guid, prev_qty:item_guid. branch_guid. prev_qty:branch_guid. quantity, updated_qty } } else { item_branch_ids:push(current_branch_id) item_branch_quantities,push({ item_guid: element.item_guid, branch_guid: current_branch_id, quantity: delta_transaction }) } t.update(itemRef; { branch_quantities. item_branch_quantities: branch_ids: item_branch_ids }) }) }) item_update_transactions.push(p) }); return Promise.all(item_update_transactions) }) function isLineTransIncrease(line_trans: number): boolean { return (line_trans === 1) || (line_trans === 2) }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么 Firebase 云 Function 执行定义的 Promise - Why does Firebase Cloud Function execute defined Promise 尝试通过云功能连接到 Firestore 时,为什么会出现“预期的捕获()或返回”错误? - Why do I get "Expected catch() or return"-error when trying to connect to firestore via cloud-function? 带有if语句的for循环不会多次运行javascript - For loop with if statement will not run more than once javascript For 循环在循环超过 1 次时不等待 promise - For loop does not await promise when looping more than 1 time JavaScript Promise EsLint 部署 Firebase-Cloud-Function 时出现问题 - JavaScript Promise EsLint Problems when deploying Firebase-Cloud-Function 为什么当无服务器 function 在 Firebase 云 Z2764085932F8B 中成功完成 Promise.all() 时退出时性能会下降? - Why does performance degrade when a serverless function exits without completing Promise.all() successfully in Firebase Cloud Function? 无法让我的 Javascript 函数在 PHP foreach 循环中多次运行 - Can't get my Javascript function to run more than once in a PHP foreach loop Firestore 云功能更新所有文档中的字段与参数 - Firestore cloud-function to update a field in all doc in coll with parameter 在Javascript(V8)中,为什么数组上的forEach比简单的for循环消耗更多的内存? - In Javascript (V8) why does forEach on an array consume much more memory than a simple for loop? 如果多次运行初始化,为什么我的jquery onclick函数会打开和关闭? - Why does my jquery onclick function toggle on and off, if I run initialization more than once?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM