簡體   English   中英

為什么 firebase cloud-function javascript promise 運行次數超過循環調用次數?

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

我有一個雲 function,當銷售/購買提交到 Firestore 時觸發。 此功能的目的是集中更新庫存水平。

如果我只在 1 個倉庫更新物品的庫存,function 工作得很好,但對多個倉庫執行此操作會出現意外行為。 我遍歷所有受影響的倉庫以計算總庫存水平變化,並且每次迭代都會啟動 javascript promise。

問題似乎與調用承諾的方式有關。 例如:如果我想更新 3 個倉庫並循環 3 次,不知何故 5 個 Promise 正在啟動。 這可以通過日志看到。 我在這里研究了類似的問題,但是在 firestore 仍處於測試階段時提出了解決方案,可能不是正確的前進方向。 Firestore 事務多次觸發導致錯誤數據

這是代碼

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 次時的日志消息

我們通過閱讀這篇文章找到了解決方案。

一個事務由任意數量的 get() 操作和任意數量的寫操作組成,例如 set()、update() 或 delete()。 在並發編輯的情況下,Cloud Firestore 會再次運行整個事務。 例如,如果一個事務讀取文檔,而另一個客戶端修改了這些文檔中的任何一個,則 Cloud Firestore 會重試該事務。 此功能可確保事務在最新且一致的數據上運行。

 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM