This is the cloud function that I'm using to send notification to the shopkeepers when an order is accepted by the shipper. But sometimes it takes at least 20 seconds to complete and more often take more than 3 minutes. My other cloud functions are working completely fine. Can't figure out the issue with this function.
exports.onChangeOfOrderStatus = functions.firestore
.document('orders/{documentId}')
.onUpdate(async (change, context) => {
// Get an object with the current document value.
// If the document does not exist, it has been deleted.
const document = change.after.exists ? change.after.data() : null;
// Get an object with the previous document value (for update or delete)
const oldDocument = change.before.data();
const newDocument = change.after.data();
const oldStatus = oldDocument.orderStatus;
const newStatus = newDocument.orderStatus;
functions.logger.log(oldStatus);
functions.logger.log('TO');
functions.logger.log(newStatus);
let orderPassed = false;
let shopsIds = [];
Array.prototype.push.apply(shopsIds, newDocument.shopsWhoGotOrders);
functions.logger.log("Printing shopIds 1st time");
shopsIds = getUnique(shopsIds);
printArray(shopsIds); //Code works fine and instantly at this point of line
let shopTokensAre = [];
if (oldStatus == 'prepending' && newStatus == 'pending') {
shopsIds.forEach(async result => {
await admin.firestore().collection("users")
.where('role', "==", 'shopkeeper')
.where('uid', '==', result)
.get().then(snapshot => {
snapshot.forEach(async doc => {
shopTokensAre.push(doc.data().token);
functions.logger.log("Printing shopIds: 2nd time"); // This line
//takes time to print
functions.logger.log(doc.data().token);
await admin.messaging().send({
token: doc.data().token,
notification: {
title: "Hi TELLOO Shopkeeper",
body: 'You received a new order, Please Accept/Reject it fastly',
imageUrl: 'https://support.kraken.com/hc/article_attachments/360085484571/ProApp_NewOrderButton_02082021.png',
}
})
.then(snapshot => {
functions.logger.log("Notifications sent");
});
});
});
});
}
});
CodePudding user response:
I suggest reviewing the Tips & Tricks guide for Cloud Functions to check the recommendations and avoid issues when using Cloud Functions.
Several of the recommendations in this document center on what is known as a cold start. Functions are stateless, and the execution environment is often initialized from scratch, which is called a cold start.
From the issue you're describing, it is most likely that it could be a cold start issue. You could check the minimum instances configured for your function.
By default, Cloud Functions scales the number of instances based on the number of incoming requests. You can change this default behavior by setting a minimum number of instances that Cloud Functions must keep ready to serve requests. Setting a minimum number of instances reduces cold starts of your application.
You can set a minimum instance limit for existing functions, by following these steps:
- Go to the Cloud Functions page in the Google Cloud Console:
Go to the Cloud Functions page- Click the name of an existing function to be taken to its Function details page.
- Click Edit.
- Click Runtime, build, and connection settings to expand additional options.
- In the Minimum instances field in the Autoscaling section, enter a number greater than or equal to 1.
- Click Next.
- Click Deploy.
Additionally, you could check the dependencies you use in your function:
Because functions are stateless, the execution environment is often initialized from scratch (during what is known as a cold start). When a cold start occurs, the global context of the function is evaluated.
If your functions import modules, the load time for those modules can add to the invocation latency during a cold start. You can reduce this latency and the time needed to deploy your function, by loading dependencies correctly and not loading dependencies your function doesn't use.
See also:
CodePudding user response:
You may see better performance avoiding the async forEach
function. I've observed a similar slowness to what you've described when a Cloud Function gets overloaded.
exports.onChangeOfOrderStatus = functions.firestore
.document('orders/{documentId}')
.onUpdate(async (change, context) => {
const oldDocument = change.before.data();
const newDocument = change.after.data();
const oldStatus = oldDocument.orderStatus;
const newStatus = newDocument.orderStatus;
if (oldStatus !== 'prepending' || newStatus !== 'pending') {
return;
}
let shopsIds = [];
Array.prototype.push.apply(shopsIds, newDocument.shopsWhoGotOrders);
shopsIds = getUnique(shopsIds);
const messagingPromises = [];
for (const shopsId of shopsIds) {
const querySnapshot = await admin
.firestore()
.collection('users')
.where('role', '==', 'shopkeeper')
.where('uid', '==', shopsId)
.get();
querySnapshot.forEach((doc) => {
const messagingPromise = admin.messaging().send({
token: doc.data().token,
notification: {
title: 'Hi TELLOO Shopkeeper',
body: 'You received a new order, Please Accept/Reject it fastly',
imageUrl:
'https://support.kraken.com/hc/article_attachments/360085484571/ProApp_NewOrderButton_02082021.png',
},
});
messagingPromises.push(messagingPromise);
});
}
await Promise.all(messagingPromises);
});