Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firestore Push Notification "time out" error Notification doesn't always get sent

I am calling a function from my app that sends a notification out to a specific user on the app. The notification gets sent successfully much of the time but a good amount of times it does not get sent. When it does not get sent I check the logs to see

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

I have tried playing with my promises / async await but have had no luck as I suspect that is where the issue lies.

Here is what my cloud code looks like now

exports.sendNotification = functions.https.onRequest(async (request, response) => {

    if (request.method !== "POST") {
        response.status(400).send("Send it using post request");
        return;
    }

    var toUid = request.body.toUid
    var fcm = request.body.fcm
    var fromUid = request.body.fromUid
    var type = request.body.type
    var fromName = request.body.fromName
    var messageText = request.body.message

    if (toUid === "" || fromUid === "" || fcm === "") {
        response.status(400).send("Parameter is missing!");
        return;
    }

    // common data for both platforms
    const notification = {
     title: fromName,
     body: messageText,
    }
    const fcmToken = fcm

    // ios specific headers
    const apns = {
      headers: {
        "apns-collapse-id": 'toUid'
      },
      payload: {
        aps: {
          sound: 'default'
        },
        "data": {
          "fromUid": fromUid,
          "type": type
        }
      }
    }

    // final message
    const message = {
     token: fcmToken,
     notification: notification,
     apns: apns,
    }

    // send message
    try {
      return await admin.messaging().send(message);
      response.status(200).send("Done");
    } catch(e) {
      console.log('Error sending message:', e);
    }
});

I call the function from the app as follows

         AF.request("https://myproject.net/sendNotification", method: .post, parameters: parameters, encoding: JSONEncoding.default)
         .responseString { response in
             print(response)
            DispatchQueue.main.async {
                completion("done")
            }
         }

I have seen other stackoverflow questions of similar questions where it was suggested to use .post and JSONEncoding.default and so that is what I have now.

like image 611
user6520705 Avatar asked Jun 30 '21 17:06

user6520705


Video Answer


1 Answers

From https://firebase.google.com/docs/functions/http-events#terminate_http_functions :

In your catch block there's no call to .send() or any equivalent, so from the link above :

Always end an HTTP function with send(), redirect(), or end(). Otherwise, your function might continue to run and be forcibly terminated by the system. See also Sync, Async and Promises.

Also it's better to wrap your entire code in the onRequest callback in a try/catch.

Here's the code with suggested fixes :

exports.sendNotification = functions.https.onRequest(async (request, response) => {

  try {

    if (request.method !== "POST") {
      response.status(400).send("Send it using post request");
      return;
    }

    var toUid = request.body.toUid
    var fcm = request.body.fcm
    var fromUid = request.body.fromUid
    var type = request.body.type
    var fromName = request.body.fromName
    var messageText = request.body.message

    if (toUid === "" || fromUid === "" || fcm === "") {
      response.status(400).send("Parameter is missing!");
      return;
    }

    // common data for both platforms
    const notification = {
      title: fromName,
      body: messageText,
    }
    const fcmToken = fcm

    // ios specific headers
    const apns = {
      headers: {
        "apns-collapse-id": 'toUid'
      },
      payload: {
        aps: {
          sound: 'default'
        },
        "data": {
          "fromUid": fromUid,
          "type": type
        }
      }
    }

    // final message
    const message = {
      token: fcmToken,
      notification: notification,
      apns: apns,
    }

    // send message
    await admin.messaging().send(message); // do not return here
    response.status(200).send("Done");

  } catch (e) {
    response.status(500).send(e) // note the .send() wich terminates the request
  }
});
like image 145
mbesson Avatar answered Nov 01 '22 08:11

mbesson