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

Posted

技术标签:

【中文标题】Firebase 函数无法使用异步 sendMulticast 方法发送一些推送通知【英文标题】:Firebase functions fails to send some push notifications using async sendMulticast method 【发布时间】:2019-09-03 17:28:49 【问题描述】:

这件事让我难过了好几天。代码很多所以希望你能坚持我..

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

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】:
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;

这对我有用

【讨论】:

以上是关于Firebase 函数无法使用异步 sendMulticast 方法发送一些推送通知的主要内容,如果未能解决你的问题,请参考以下文章

Firebase 函数无法部署:SyntaxError: Unexpected token function

为啥使用异步函数“getDownloadURL”来获取 Firebase 存储中的文件 URL

Firebase 异步等待风格的云函数

Flutter:关于检索 Firebase 用户 ID 的异步函数的问题

在 React-Native 中的非异步函数中调用异步函数 - Firebase

如何使用 Firebase 处理异步数据库?