Firebase函数无法使用异步sendMulticast方法发送一些推送通知

时间:2019-04-12 22:39:34

标签: typescript firebase async-await firebase-cloud-messaging

这个让我难过了几天。有很多代码,所以希望您能坚持下去。

我将您在下面看到的所有代码编译到一个地方,以使其更容易:

https://stackblitz.com/edit/angular-us7xwt

好的,让我们开始吧!

我每天运行一次cron作业,以在用户有新音乐时通知用户,以检查哪些触发了Firebase功能。要查询发布,我的网站API返回一个对象数组,其中包含用户和他们所关注的艺术家以及今天发布音乐的艺术家:

触发Firebase函数后运行的API调用

axios.get(`${apiURL}...`).then((response) => {
    var users = response.data;
    if(users.length > 0) {
        createTopics(users)
    }
})

此API调用返回的数据的格式如下,并存储在上面的users变量中。如果已填充数组,则运行createTopics(users)

  [{
    "userUID": "kaLOIkGwrWO4DSFP41OmfozxhsN2",
    "artists": [
      "Adventure Club",
      "LSD",
      "Marshmello"
    ]
  },
  {
    "userUID": "ZvOBNBqxbgRYoibSYEwkL9YKtWG2",
    "artists": [
      "Krewella",
      "Lolo Zouaï",
      "The Chemical Brothers"
    ]
  }]

createTopics()

这将为每个用户生成推送通知的元数据。创建消息后,我需要查询特定用户拥有的所有设备,以便可以使用Firebase的multicast()

向所有设备推送通知
function createTopics(users) {

    users.forEach((user: any) => {

        const message = {
            notification: {
                title: `my title`,
                body: `my body`
            },
            tokens: null
        }
        // tslint:disable-next-line:no-floating-promises
        findUserDevices(user.userUID, message);
    })
}

findUserDevices()

此函数在我的Firestore数据库中查询发送推送通知所需的特定用户的设备令牌。如果我们的数据库中存在该用户的设备,则需要将消息推送到他们的设备。

function findUserDevices(uid: string, message) {
    collectionData(fb.firestore().collection('devices').where('userId', '==', uid)).pipe(
        filter((userDevices) => userDevices && userDevices.length > 0),
        take(1)
    ).subscribe((devices: any) => {
        var userDeviceTokens: string[] = devices.map((device: any) => device.token);
        console.log(userDeviceTokens)
        if (userDeviceTokens !== undefined && userDeviceTokens.length != 0) {
            // tslint:disable-next-line:no-floating-promises
            pushToDevices(userDeviceTokens, message);
        }
    })
}

pushToDevices()

以下是一个异步功能,用于将消息推送到设备...也许这是哪里出错了?我将令牌附加到payload上,然后使用sendMulticast()。根据此方法的响应,如果任何令牌失败,我将使用deleteOldToken()异步调用将其删除。

async function pushToDevices(userDeviceTokens, payload) {
    payload['tokens'] = userDeviceTokens;
    await admin.messaging().sendMulticast(payload).then((response) => {
        console.log('Success:', response);
        if (response.failureCount > 0) {
            const failedTokens = [];
            response.responses.forEach((resp, idx) => {
                if (!resp.success) {
                    failedTokens.push(userDeviceTokens[idx]);
                }
            });
            failedTokens.forEach((token) => {
                var tokenInstanceID = token.split(':')[0];
                // tslint:disable-next-line:no-floating-promises
                deleteOldToken(tokenInstanceID);
            })
          }
    })
        .catch((error) => {
            console.log('Error:', error)
    });
}

deleteOldToken()

async function deleteOldToken(tokenInstanceID) {
    await fb.firestore().collection('devices').doc(tokenInstanceID).delete().then(() => {
        console.log(`Token ${tokenInstanceID} deleted`)
    })
}

这就是整个方法,这是我的日志

看看我的控制台日志,我看到了一系列奇怪的活动,以及几行超时错误

Error: { Error: Error while making request: timeout of 10000ms exceeded.
    at FirebaseAppError.Error (native)
    at FirebaseAppError.FirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:42:28)
    at FirebaseAppError.PrefixedFirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:88:28)
    at new FirebaseAppError (/user_code/node_modules/firebase-admin/lib/utils/error.js:122:28)
    at /user_code/node_modules/firebase-admin/lib/utils/api-request.js:152:23
    at process._tickDomainCallback (internal/process/next_tick.js:135:7)
  errorInfo: 
   { code: 'app/network-timeout',
     message: 'Error while making request: timeout of 10000ms exceeded.' },
  codePrefix: 'app' }

混合了几行连接重置错误:

Error: { Error: Error while making request: read ECONNRESET. Error code: ECONNRESET
    at FirebaseAppError.Error (native)
    at FirebaseAppError.FirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:42:28)
    at FirebaseAppError.PrefixedFirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:88:28)
    at new FirebaseAppError (/user_code/node_modules/firebase-admin/lib/utils/error.js:122:28)
    at /user_code/node_modules/firebase-admin/lib/utils/api-request.js:154:19
    at process._tickDomainCallback (internal/process/next_tick.js:135:7)
  errorInfo: 
   { code: 'app/network-error',
     message: 'Error while making request: read ECONNRESET. Error code: ECONNRESET' },
  codePrefix: 'app' }

最后,有些方法可以完美地工作:

Success: { responses: 
   [ { success: true,
       messageId: 'projects/release-hub-f3f5f/messages/1555102845415084' },
     { success: true,
       messageId: 'projects/release-hub-f3f5f/messages/0:1555102845414983%f95cf250f95cf250' } ],
  successCount: 2,
  failureCount: 0 }

与我的一些用户联系后,一些用户收到了他们的推送通知,而许多用户则没有。我有预感,这与我的异步调用有关,但是我在哪里出错呢?非常感谢您坚持这个问题,如果您需要更多信息,请告诉我。

1 个答案:

答案 0 :(得分:0)

var message = new MulticastMessage()
            {
                Tokens = clientTokens,
                Data = new Dictionary<string, string>()
                     {
                     {"title", title},
                     {"body", body},
                     },
                Notification = new Notification()
                {
                    Title = title , 
                    Body = body
                }
            };
            var response = FirebaseMessaging.DefaultInstance.SendMulticastAsync(message).Result;

这对我有用