在运行一堆Firebase查询之后的60秒内Firebase超时云功能 [英] Cloud Function for Firebase timeout after 60 seconds while running a bunch of Firebase queries

查看:318
本文介绍了在运行一堆Firebase查询之后的60秒内Firebase超时云功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Firebase作为群组协作应用程式(例如Whatsapp),我正在使用云端功能找出哪些手机联络人也使用我的应用程式(又类似于Whatsapp)。云功能运行良好,直到我开始看到一些调用函数日志中的以下日志。
$ b

函数执行花了60023毫秒,完成状态:'超时'



我做了一些调试,发现对于这个特定的用户,他的手机通讯录上有很多联系人很明显,找出哪些联系人正在使用应用程序所需的工作也增加到了超过60秒的时间。以下是Cloud Function的代码

$ $ p $ $ $ c $ // contactsData是用户手机上的一组联系人
//每个联系人可以包含多个电话号码,这些电话号码是
//存在于phoneNumbers数组中。因此,本质上,我们需要
//来查询用户联系簿中的所有电话号码。
contactsData.forEach((contact)=> {
contact.phoneNumbers.forEach(( phoneNumber)=> {
//查找具有此phoneNumber的用户是否正在使用应用程序
//检查mobileNumber和mobileNumberWithCC
promises.push(ref.child('users')。 orderByChild(mobileNumber)。
equalTo(phoneNumber.number).once(value)。then(usersSnapshot => {
// usersSnapshot应该只包含一个条目,假设
/ / phoneNumber对于用户来说是唯一的
if(!usersSnapshot.exists()){
return null
}
var user = null
usersSnapshot.forEach (userSnapshot => {
user = userSnapshot.val()
})
return {
name:contact .name,
mobileNumber:phoneNumber.number,
id:user.id
}
}))
promises.push(ref.child('users') .orderByChild( mobileNumberWithCC)。
equalTo(phoneNumber.number).once(value)。then(usersSnapshot => {
// usersSnapshot应该只包含一个条目,假设
// phoneNumber将是唯一的(!usersSnapshot.exists()){
return null
}
var user = null
usersSnapshot.forEach(userSnapshot => {
user = userSnapshot.val()
})
return {
名称:contact.name,
mobileNumber:phoneNumber.number,
id:user。 id
}
}))
});
});
return Promise.all(promises)
))。then(allContacts => {
// allContacts是一个空数组和联系人数组
//摆脱null和返回数组中的任何重复条目
currentContacts = arrayCompact(allContacts)

//创建contactsObj,用户的联系人正在使用应用程序
currentContacts.forEach contact => {
contactsObj [contact.id] = contact
))
//返回当前联系人
返回ref.child('userInfos')。child ('contacts').child('contacts')。once('value')
})。then((contactsSnapshot)=> {
if(contactsSnapshot.exists()){
contactsSnapshot .forEach((contactSnapshot)=> {
previousContacts.push(contactSnapshot.val())
})
}
//在更新firease上的联系人后以前的联系人
ref.child('userInfos ).child(uid).child('contacts').set(contactsObj)

//找出新的,删除的和重命名的联系人
newContacts = arrayDifferenceWith(currentContacts,previousContacts,
(obj1,obj2)=> (obj1.id === obj2.id))
deletedContacts = arrayDifferenceWith(previousContacts,currentContacts,
(obj1,obj2)=>(obj1.id === obj2.id))
renamedContacts = arrayIntersectionWith(currentContacts,previousContacts,
(obj1,obj2)=>(obj1.id === obj2.id&& obj1.name!== obj2.name))
//创建deletedContactsObj存储在firebase上
deletedContacts.forEach((deletedContact)=> {
deletedContactsObj [deletedContact.id] = deletedContact
})
// Get删除的联系人
返回ref.child('userInfos')。child(uid).child('deletedContacts')。once('value')
})。then((deletedContactsSnapshot)=> (删除接触快照。存在()){
deletedContactsSnapshot.forEach((deletedContactSnapshot)=> {
priorDeletedContacts.push(deletedContactSnapshot.val())
})
}
//联系人w以前删除,但现在再次添加
restoredContacts = arrayIntersectionWith(newContacts,previouslyDeletedContacts,
(obj1,obj2)=> (obj1.id === obj2.id))
//从deletedContacts中删除已恢复的联系人
restoredContacts.forEach((restoredContact)=> {
deletedContactsObj [restoredContact.id] = null
})
//使用任何已删除的,新的或重命名的联系人更新组
返回ContactsHelper.processContactsData(uid,deletedContacts,newContacts,renamedContacts)
})。然后(()=> {
//检索先前deletedContacts
后设置返回ref.child('userInfos')。child(uid).child('deletedContacts').update(deletedContactsObj)





$ b

以下是一些示例数据

  //这是一个示例contactsData 
[
{
phoneNumbers:[
{
号码:12324312321,
label:home
},
{
number:2322412132,
label:工作


g ivenName:blah5,
familyName:,
middleName:
},
{
phoneNumbers:[
$ b $ number $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $' b $ bfamilyName:blah4,
middleName:
},
{
phoneNumbers:[
{
number:1234567890,
label:mobile
}
],
givenName:blah1,
familyName: blah2,
middleName:
}
]



//这是用户存储在Firebase 。这可能是很多用户
users:{
id1:{
countryCode:91,
id:id1,
mobileNumber:1231211232,
mobileNumberWithCC:911231211232,
name:Varun
},
id2:{
countryCode:1,
id:id2,
mobileNumber:2342112133,
mobileNumberWithCC:12342112133,
name:Ashish
},
id3:{
countryCode:1,
id:id3,
mobileNumber:b
mobileNumberWithCC:1123213421,
在这种特殊情况下, contactsData 包含了 1046 <$ c $>

> / code>条目,其中一些条目中有两个 phoneNumbers 。所以,我们假设有一个总数 1500 的电话号码,我需要检查。我正在创建查询来针对数据库中的用户比较 mobileNumber mobileNumberWithCC 。所以,总共有 3000 查询,这个函数会在promise完成之前做出来,我猜测完成所有这些查询需要花费超过60秒的时间,我的几个问题是:


  1. 是不是预计所有这些查询需要超过60秒?考虑到它在Firebase基础架构中运行,我预计它会更快完成。

  2. 有没有办法增加函数的超时限制?我现在正在Blaze计划中。

为了缓解这个问题,我还会明白上述功能的另一个实现建议。如果你不能避免查询这么多的数据,你可以改变函数的超时时间解决方案

https://console.cloud.google.com/ =nofollow noreferrer>云控制台为您的项目使用左侧的功能产品。目前,您将不得不重置每个新部署的超时。


I am using Firebase for a group collaboration app (like Whatsapp) and I am using a Cloud Function to figure out which of the phone contacts are also using my app (again similar to Whatsapp). The Cloud Function ran fine till I started to see the following log in the Functions Log for some invocations.

Function execution took 60023 ms, finished with status: 'timeout'

I did some debugging and found that for this particular user, he has a lot of contacts on his phone's contacts book and so obviously the work required to figure out which of those contacts are using the app also increased to a point that it took more than 60 secs. Below is the code for the Cloud Function

      // contactsData is an array of contacts on the user's phone
      // Each contact can contain one more phone numbers which are
      // present in the phoneNumbers array. So, essentially, we need
      // to query over all the phone numbers in the user's contact book
      contactsData.forEach((contact) => {
        contact.phoneNumbers.forEach((phoneNumber) => {
          // Find if user with this phoneNumber is using the app
          // Check against mobileNumber and mobileNumberWithCC
          promises.push(ref.child('users').orderByChild("mobileNumber").
            equalTo(phoneNumber.number).once("value").then(usersSnapshot => {
              // usersSnapshot should contain just one entry assuming
              // that the phoneNumber will be unique to the user
              if(!usersSnapshot.exists()) {
                return null
              }
              var user = null
              usersSnapshot.forEach(userSnapshot => {
                user = userSnapshot.val()
              })
              return {
                name: contact.name,
                mobileNumber: phoneNumber.number,
                id: user.id
              }
            }))
          promises.push(ref.child('users').orderByChild("mobileNumberWithCC").
            equalTo(phoneNumber.number).once("value").then(usersSnapshot => {
              // usersSnapshot should contain just one entry assuming
              // that the phoneNumber will be unique to the user
              if(!usersSnapshot.exists()) {
                return null
              }
              var user = null
              usersSnapshot.forEach(userSnapshot => {
                user = userSnapshot.val()
              })
              return {
                name: contact.name,
                mobileNumber: phoneNumber.number,
                id: user.id
              }
            }))
        });
      });
      return Promise.all(promises)
    }).then(allContacts => {
      // allContacts is an array of nulls and contacts using the app
      // Get rid of null and any duplicate entries in the returned array
      currentContacts = arrayCompact(allContacts)

      // Create contactsObj which will the user's contacts that are using the app
      currentContacts.forEach(contact => {
        contactsObj[contact.id] = contact
      })
      // Return the currently present contacts
      return ref.child('userInfos').child(uid).child('contacts').once('value')
    }).then((contactsSnapshot) => {
      if(contactsSnapshot.exists()) {
        contactsSnapshot.forEach((contactSnapshot) => {
          previousContacts.push(contactSnapshot.val())
        })
      }
      // Update the contacts on firease asap after reading the previous contacts
      ref.child('userInfos').child(uid).child('contacts').set(contactsObj)

      // Figure out the new, deleted and renamed contacts
      newContacts = arrayDifferenceWith(currentContacts, previousContacts, 
        (obj1, obj2) => (obj1.id === obj2.id))
      deletedContacts = arrayDifferenceWith(previousContacts, currentContacts,
        (obj1, obj2) => (obj1.id === obj2.id))
      renamedContacts = arrayIntersectionWith(currentContacts, previousContacts,
        (obj1, obj2) => (obj1.id === obj2.id && obj1.name !== obj2.name))
      // Create the deletedContactsObj to store on firebase
      deletedContacts.forEach((deletedContact) => {
        deletedContactsObj[deletedContact.id] = deletedContact
      })
      // Get the deleted contacts
      return ref.child('userInfos').child(uid).child('deletedContacts').once('value')
    }).then((deletedContactsSnapshot) => {
      if(deletedContactsSnapshot.exists()) {
        deletedContactsSnapshot.forEach((deletedContactSnapshot) => {
          previouslyDeletedContacts.push(deletedContactSnapshot.val())
        })
      }
      // Contacts that were previously deleted but now added again
      restoredContacts = arrayIntersectionWith(newContacts, previouslyDeletedContacts,
        (obj1, obj2) => (obj1.id === obj2.id))
      // Removed the restored contacts from the deletedContacts
      restoredContacts.forEach((restoredContact) => {
        deletedContactsObj[restoredContact.id] = null
      })
      // Update groups using any of the deleted, new or renamed contacts
      return ContactsHelper.processContactsData(uid, deletedContacts, newContacts, renamedContacts)
    }).then(() => {
      // Set after retrieving the previously deletedContacts
      return ref.child('userInfos').child(uid).child('deletedContacts').update(deletedContactsObj)
    })

Below is some sample data

// This is a sample contactsData
[
  {
    "phoneNumbers": [
      {
        "number": "12324312321",
        "label": "home"
      },
      {
        "number": "2322412132",
        "label": "work"
      }
    ],
    "givenName": "blah5",
    "familyName": "",
    "middleName": ""
  },
  {
    "phoneNumbers": [
      {
        "number": "1231221221",
        "label": "mobile"
      }
    ],
    "givenName": "blah3",
    "familyName": "blah4",
    "middleName": ""
  },
  {
    "phoneNumbers": [
      {
        "number": "1234567890",
        "label": "mobile"
      }
    ],
    "givenName": "blah1",
    "familyName": "blah2",
    "middleName": ""
  }
]



// This is how users are stored on Firebase. This could a lot of users
  "users": {
    "id1" : {
      "countryCode" : "91",
      "id" : "id1",
      "mobileNumber" : "1231211232",
      "mobileNumberWithCC" : "911231211232",
      "name" : "Varun"
    },
    "id2" : {
      "countryCode" : "1",
      "id" : "id2",
      "mobileNumber" : "2342112133",
      "mobileNumberWithCC" : "12342112133",
      "name" : "Ashish"
    },
    "id3" : {
      "countryCode" : "1",
      "id" : "id3",
      "mobileNumber" : "123213421",
      "mobileNumberWithCC" : "1123213421",
      "name" : "Pradeep Singh"
    }
  }

In this particular case, the contactsData contained 1046 entries and for some of those entries, there were two phoneNumbers. So, let's assume there were a total of 1500 phone numbers that I need to check. I am creating queries to compare against the mobileNumber and mobileNumberWithCC for the users in the database. So, there are a total of 3000 queries that the function will make before the promise finishes and I am guessing it is taking more than 60 seconds to finish up all those queries and hence the Cloud Function timed out.

My few questions are:

  1. Is it expected for all those queries to take more than 60 secs? I was expecting it to finish much faster given that it is running within the Firebase infrastructure.
  2. Is there a way to increase the timeout limit for a function? I am currently on Blaze plan.

I will also appreciate any alternate implementation suggestions for the above function in order alleviate the problem. Thanks!

解决方案

If you cannot avoid querying so much data, you can change the timeout of a function in the Cloud Console for your project using the Functions product on the left. Currently, you will have to reset the timeout with each new deploy.

这篇关于在运行一堆Firebase查询之后的60秒内Firebase超时云功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆