Search code examples
javascriptfirebase-realtime-databasegoogle-cloud-functionses6-promise

Google Cloud Functions Promises execution and return


I have a Google Cloud maintenance function I wish to run to update a Firebase Real-time Database. The code is pretty straight forward, but for some reason the execution finishes before all code is run. I suspect that my await call is not handled as expected because I am miss-using .once()?

exports.setUserLimits = functions
.region('europe-west1')
.database
.ref('/NO-TRIGGER')
.onCreate(async (snapshot, context) => {
  let myPromises = []
  const userNodeSnap = await database.ref('users').once('value')
  console.log('numChildren', userNodeSnap.numChildren())
  userNodeSnap.forEach(async (userSnap) => {
    console.log('Process user', userSnap.key)
    const userData = userSnap.val()
    //Set user limits
    const limits = {items:10, logins:1}
    console.log('New limits', limits)
    myPromises.push(userSnap.ref.update({limits}))
  })

  // Execute all promises
  console.log('myPromises lenght', myPromises.length)
  return Promise.all(myPromises)
  .then(()=>{
    return Promise.resolve()
  })
  .catch((err)=>{
    console.error('Could not execute all promises', err)
    // Show must go on!
    return Promise.resolve()
  })
})

Logout from Google Cloud Functions

setUserLimits Function execution started
numChildren 4
Process user 1234567890
myPromises lenght 0
Function execution took 416 ms, finished with status: 'ok'
New limits {items:10, logins:1}

The execution finishes prematurely resulting in only one record being updated.

Replacing the last lines to below generates the same result

await Promise.all(myPromises)

/K


Solution

  • If we look at this block of code:

      userNodeSnap.forEach(async (userSnap) => {
        console.log('Process user', userSnap.key)
        const userData = userSnap.val()
        //Set user limits
        const limits = {items:10, logins:1}
        console.log('New limits', limits)
        myPromises.push(userSnap.ref.update({limits}))
      })
    

    we see that it has the logical form:

    someArray.forEach(async function(element) {
      // do something
    });
    

    Basically, code after the forEach function call can execute before the completion of processing of each element of the aray.