简体   繁体   中英

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. 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. 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.

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. 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 transactions getting triggered multiple times resulting in wrong data )

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(). In the case of a concurrent edit, Cloud Firestore runs the entire transaction again. For example, if a transaction reads documents and another client modifies any of those documents, Cloud Firestore retries the transaction. 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) }

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