Ошибка времени ожидания push-уведомлений Firestore Уведомление не всегда отправляется

Я вызываю функцию из своего приложения, которая отправляет уведомление определенному пользователю в приложении. В большинстве случаев уведомление отправляется успешно, но в большинстве случаев оно не отправляется. Когда он не приходит, я проверяю журналы, чтобы увидеть

Выполнение функции заняло 60003 мс, завершено со статусом «тайм-аут».

Я попытался поиграть с моими обещаниями / async await, но мне не повезло, поскольку я подозреваю, что в этом и заключается проблема.

Вот как сейчас выглядит мой облачный код

      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);
    }
});

Я вызываю функцию из приложения следующим образом

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

Я видел другие вопросы о stackoverflow с похожими вопросами, где предлагалось использовать .post и JSONEncoding.default, и это то, что у меня есть сейчас.

2 ответа

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

В вашем блоке catch нет вызова .send()или любой эквивалент, поэтому по ссылке выше:

Всегда завершайте функцию HTTP с помощью send(), redirect() или end(). В противном случае ваша функция может продолжать работать и быть принудительно завершена системой. См. также Синхронизация, асинхронность и обещания.

Также лучше обернуть весь код в onRequestобратный вызов в try/catch.

Вот код с предлагаемыми исправлениями:

      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
  }
});

Я ни в коем случае не эксперт по узлам, но некоторое время играл с Firebase Messaging и придумал работающее асинхронное решение для отправки уведомления на основе создания данных в базе данных реального времени. Единственное другое отличие, помимо триггера, которое я действительно вижу, это то, что я еще не отправляю специальный заголовок APNS ...

Я также вспоминаю, что у меня периодически возникала проблема с тайм-аутом, когда я пытался использовать асинхронный вот почему я использую там обещания.

      exports.onMessageCreate = functions.database
.ref('/users/{userId}/notifications/unread/{notificationId}')
.onCreate(async (snapshot, context) => {
    
    const message = snapshot.val()
    const category = message.category
    const title = category + ": " + message.title
    const text = message.text
    const forUserId = message.forUserId
    const date = message.date
    
    const token = await getUserToken(forUserId)
    
    if (token == null) {
        throw new functions.https.HttpsError('unavailable', 'The token is nil, unable to send message')
    }
    
    const notification = {
        notification: {
            title: title,
            body: text
        },
        data: {
            category: category,
            title: message.title,
            text: text,         
            forUserId: forUserId,
            date: date.toString()
        },
        token: token
    }
    
    return admin.messaging().send(notification)
    .then((response) => {
        console.log('Successfully sent notification:', response)
    })
    .catch((error) => {
        console.log('Error sending notification:', error)
    })
    
})
Другие вопросы по тегам