I am trying to understand how to properly use a cloud function..
The cloud function below achieves the desired result, however, I am not using a 'return' in it.
is this an issue? if yes, how do I solve it?
exports.onJobChangeToClosedAndSubstateIsCancelled = functions.firestore
.document("job/{docId}")
.onUpdate(async (change, eventContext) => {
const afterSnapData = change.after.data();
const afterJobState = afterSnapData["Job state"];
const afterJobSubState = afterSnapData["Job substate"];
if (afterJobSubState == "Cancelled" && afterJobState == "Closed") {
// get all job related job applications
const relatedJobApplicationsList = await admin.firestore().collection("job application").where("Job id", "==", change.before.id).get();
// mark job applications closed so that other contractors cant waste their time
relatedJobApplicationsList.forEach(async doc => {
await admin.firestore().collection("job application").doc(doc.id).update({
"Job application state": "Closed",
"Job application substate": "Job cancelled by client",
})
})
}
});
My understanding from other questions such as the one below is that I should be returning the change on the document or the action taking place. ( is this correct? ) Can you help me?-firebase-function-onUpdate
Below is an example of a cloud function where I was able to place the 'return' statement:
// when a chat message is created
// send a notification to the user who is on the other side of the chat
// update the chat 'Chat last update' so that the Chats screen can put the chat at the top of the page
exports.onChatMessageCreate = functions.firestore
.document("chat messages/{docId}")
.onCreate(async (snapshot, context) => {
const snapData = snapshot.data();
// information about who sent the message
const senderUserName = snapData["Chat message creator first name"];
const senderUserId = snapData["User id"];
// chat id to which chat messages belong to
const chatId = snapData["Chat id"];
// information about who should receive the message
let receiverUserId;
let receiverToken = "";
// fetch user to send message to
const chatData = await (await admin.firestore().collection("chat").doc(chatId).get()).data();
const chatUsersData = chatData["User ids list"];
chatUsersData[0] == senderUserId ? receiverUserId = chatUsersData[1] : receiverUserId = chatUsersData[0];
receiverToken = await (await admin.firestore().collection("user token").doc(receiverUserId).get()).data()["token"];
console.log("admin.firestore.FieldValue.serverTimestamp():: " admin.firestore.FieldValue.serverTimestamp());
// set chat last update
await admin.firestore().collection("chat").doc(chatId).update({
"Chat last update": admin.firestore.FieldValue.serverTimestamp(),
});
const payload = {
notification: {
title: senderUserName,
body: snapData["Chat message"],
sound: "default",
},
data: {
click_action: "FLUTTER_NOTIFICATION_CLICK",
message: "Sample Push Message",
},
};
return await admin.messaging().sendToDevice(receiverToken, payload);
});
CodePudding user response:
Is this an issue?
Yes, by not returning a Promise (or a value since your callback function is async
) you are incorrectly managing the life cycle of your Cloud Function.
In your case, since you have an if block, the easiest is to just do return null;
(or return 0;
or return;
) at the end of the CF as follows.
In addition, you need to use Promise.all()
since you want to execute a variable number of calls to an asynchronous method in parallel.
exports.onJobChangeToClosedAndSubstateIsCancelled = functions.firestore
.document("job/{docId}")
.onUpdate(async (change, eventContext) => {
const afterSnapData = change.after.data();
const afterJobState = afterSnapData["Job state"];
const afterJobSubState = afterSnapData["Job substate"];
if (afterJobSubState == "Cancelled" && afterJobState == "Closed") {
// get all job related job applications
const relatedJobApplicationsList = await admin.firestore().collection("job application").where("Job id", "==", change.before.id).get();
// mark job applications closed so that other contractors cant waste their time
const promises = [];
relatedJobApplicationsList.forEach(doc => {
promises.push(admin.firestore().collection("job application").doc(doc.id).update({
"Job application state": "Closed",
"Job application substate": "Job cancelled by client",
}));
})
await Promise.all(promises);
}
return null;
});
More info on how to properly manage CF life cycle here in the doc.
You may also be interested by watching the talk I gave at the I/O Extended UK & Ireland event in 2021. This talk was specifically dedicated to this subject.