Я использую Firebase для приложения для групповой совместной работы (например, Whatsapp) и использую облачную функцию, чтобы выяснить, какие из телефонных контактов также используют мое приложение (опять же аналогично Whatsapp). Облачная функция работала нормально, пока я не начал видеть следующий журнал в журнале функций для некоторых вызовов.
Function execution took 60023 ms, finished with status: 'timeout'
Я провел некоторую отладку и обнаружил, что для этого конкретного пользователя у него есть много контактов в книге контактов его телефона, и поэтому очевидно, что работа, необходимая для выяснения того, какие из этих контактов используют приложение, также увеличилась до такой степени, что потребовалось более 60 сек. Ниже приведен код облачной функции.
// 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)
})
Ниже приведены некоторые примеры данных
// 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"
}
}
В этом конкретном случае contactsData содержало 1046 записей, а для некоторых из этих записей было два phoneNumbers. Итак, давайте предположим, что мне нужно проверить 1500 телефонных номеров. Я создаю запросы для сравнения с mobileNumber и mobileNumberWithCC для пользователей в базе данных. Итак, есть в общей сложности 3000 запросов, которые функция выполнит до того, как обещание завершится, и я предполагаю, что для завершения всех этих запросов требуется более 60 секунд, и, следовательно, время ожидания облачной функции истекло.
Мои несколько вопросов:
- Ожидается ли, что все эти запросы займут более 60 секунд? Я ожидал, что он завершится намного быстрее, учитывая, что он работает в инфраструктуре Firebase.
- Есть ли способ увеличить лимит времени ожидания для функции? В настоящее время я нахожусь на плане Blaze.
Я также буду признателен за любые альтернативные предложения по реализации вышеуказанной функции, чтобы облегчить проблему. Спасибо!
Promise.all. - person Varun Gupta   schedule 05.04.2017usersбазы данных, и я храню очень минимальную информацию о каждом пользователе. Теперь пользователь запускает приложение, и у него есть 1000 контактов в этой книге контактов, и мне нужно выяснить, какие из этих 1000 контактов используют приложение. Итак, мне нужно будет выполнить как минимум 1000 запросов. Если все эти 1000 контактов используют приложение, я буду использовать результат всех этих запросов. - person Varun Gupta   schedule 06.04.2017usersSnapshot.forEach(userSnapshot => { user = userSnapshot.val() })вы повторяете все в usersSnapshot, но запоминаете только одного пользователя из этой коллекции, независимо от того, что было последним. Может быть, было бы полезно, если бы вы добавили несколько комментариев о том, чего вы пытаетесь достичь на каждом этапе, вместе с образцом некоторых данных, потому что сложно представить, что вы все здесь структурировали. - person Doug Stevenson   schedule 06.04.2017usersSnapshotбудет только один пользователь. Я перебираюcontactsData, который представляет собой массив телефонных контактов. У каждого контакта может быть несколько телефонных номеров, но обычно только один. Итак, зацикливаем каждый номер телефона в контакте. Затем я запускаюref.child('users').orderByChild("mobileNumber").equalTo(phoneNumber.number).once("value")запрос, чтобы проверить, использует ли пользователь с этим номером телефона приложение, которое должно быть только одним пользователем. Поскольку он будет возвращен какDataSnapshot, а мне нужна фактическая запись пользователя, я делаюforEach. 1/2 - person Varun Gupta   schedule 06.04.2017