云功能和承诺的新手。我尝试在不同位置添加Promise,但仍将消息记录在日志中。首先,我不确定应该在哪里添加承诺,其次我是否应该不返回任何东西。调用match之后,不需要执行其他功能(如果满足条件,则可以创建频道)。触发onCreate时将有多个用户,因此我想确保一次执行一个用户。
const functions = require('firebase-functions');
const admin = require('firebase-admin')
admin.initializeApp();
//every time user added to liveLooking node
exports.command = functions.database
.ref('liveLooking/{uid}')
.onCreate((snap, context) => {
const uid = context.params.uid
match(uid)
})
function match(uid) {
let m1uid, m2uid
admin.database().ref('liveChannels').transaction((data) => {
//if no existing channels then add user to liveChannels
if (data === null) {
console.log(`${uid} waiting for match`)
return { uid: uid }
}
else {
m1uid = data.uid
m2uid = uid
if (m1uid === m2uid) {
console.log(`$m1uid} tried to match with self!`)
//match user with liveChannel user
} else {
console.log(`matched ${m1uid} with ${m2uid}`)
createChannel(m1uid, m2uid)
return null
}
}
},
(error, committed, snapshot) => {
if (error) {
throw error
}
else {
return {
committed: committed,
snapshot: snapshot
}
}
},
false)
}
function createChannel(uid1, uid2) {
// Add channels for each user matched
const channel_id = uid1+uid2
console.log(`starting channel ${channel_id} with uid1: ${uid1}, uid2: ${uid2}`)
const m_state1 = admin.database().ref(`liveUsers/${uid1}`).set({
channel: channel_id
})
const m_state2 = admin.database().ref(`liveUsers/${uid2}`).set({
channel: channel_id
})
}
编辑1-我尝试将事务更改为使用等待,以便仅在事务之后才更改userLives节点。得到这两个警告。 1)预期在异步函数“ match”的末尾返回一个值。 2)在*** return处,箭头函数期望返回值。如果使用self匹配,我不会尝试更改LiveChannels下的任何内容。不知道如何解决该警告。 3)仍然在日志中得到函数返回未定义,期望的承诺或值-我认为是命令函数。
async function match(uid) {
let m1uid, m2uid;
let createChannel = false
try {
const transactionResult = await admin
.database()
.ref("liveChannels")
.transaction(
(data) => {
if (data === null) {
console.log(`${uid} waiting for match`)
return { uid: uid }
}
else {
m1uid = data.uid
m2uid = uid
if (m1uid === m2uid) {
console.log(`$m1uid} tried to match with self!`)
***return***
} else {
console.log(`matched ${m1uid} with ${m2uid}`)
createChannel = true
return {}
}
}
},
(error, committed, snapshot) => {
if (error) {
throw error
}
else {
return {
committed: committed,
snapshot: snapshot
}
}
},
false
);
if (transactionResult) {
if (createChannel) {
const channel_id = m1uid + m2uid
console.log(`starting channel ${channel_id} with uid1: ${m1uid}, uid2: ${m2uid}`)
const m_state1 = admin.database().ref(`liveUsers/${m1uid}`).set({
channel: channel_id
})
const m_state2 = admin.database().ref(`liveUsers/${m2uid}`).set({
channel: channel_id
})
return Promise.all([m_state1, m_state2])
}
}
} catch (err) {
throw new Error(err);
}
}
答案 0 :(得分:1)
您没有正确管理the life cycle of your Cloud Function。您需要等待所有异步任务(即对Firebase异步方法的调用)完成,然后再向平台指示它可以清除该函数。应该通过返回一个Promise来完成此操作,更准确地说,因为您通过返回promises chain链接了几个异步方法调用,所以可以完成此操作。
但是,您的Cloud Function中还有另一个问题,与您编写Transaction
的方式有关。事务自动修改调用事务的位置(即Reference
)上的数据。
在您的代码中,您在ref('liveChannels')
上调用事务,但是在事务中 内,您在其他位置修改数据:ref(`liveUsers/${uid1}`)
和ref(`liveUsers/${uid2}`)
。
这不是正确的方法:如果要将所有这些操作封装在一个事务中,则需要在一个数据库节点上调用事务,该数据库节点包含要更改的所有节点/位置,即公共父/祖先liveChannels
,liveUsers/${uid1}
和liveUsers/${uid2}
的节点。
如果我不认为这三个节点的唯一公共父/祖先节点是数据库根节点。在数据库根节点上调用事务可能不是一个好主意,尤其是当您有大量用户同时使用您的应用程序时。您应该修改数据模型(数据库结构)来避免这种情况。
还请注意,您不应使用Tansaction的onComplete
回调来处理其成功和失败,而应使用Transaction返回的Promise,以便在Promise链中正确使用它(请参见第一段) )。