AWS Pinpoint通过FCM发送重复推送问题排查与解决求助
问题原因分析
可能的触发因素
- 重复的设备Token:
getAllDeviceTokensForUser方法返回了重复的FCM Token,导致循环中对同一个Token发起两次推送请求,生成两个不同的请求ID。 - SDK使用错误:代码同时混用回调函数和
.promise()调用sendMessages——虽不会直接导致重复发送,但会让逻辑混乱,增加调试难度,容易误判请求执行次数。 - Pinpoint服务端重试:若第一次推送请求响应超时或Pinpoint未收到确认,服务端可能自动重试发送,从而产生两条推送记录。
- 函数重复调用:业务逻辑中可能意外触发两次
sendPushNotification函数,导致同一用户收到重复推送。
Node.js端解决方案(适配aws-sdk v2.1266.0)
1. 修复后的完整代码
export const sendPushNotification = async (userId: number, payload: RealTimeNotificationPayload) => { const deviceTokens = await getAllDeviceTokensForUser(userId); // 对设备Token去重,避免重复推送 const uniqueDeviceTokens = [...new Set(deviceTokens)]; logInfo('uniqueDeviceTokens==', uniqueDeviceTokens) const tokensTobeRemoved: string[] = []; // 复用Pinpoint实例,移出循环减少资源消耗 const pinpoint = new AWS.Pinpoint(); const pushNotificationPromises = uniqueDeviceTokens.map(async (deviceToken) => { const params = { ApplicationId: commonConfig.aws.pinPointApplicationId, // 添加幂等Token,防止服务端重试导致重复推送 ClientRequestToken: `${userId}-${deviceToken}-${Date.now()}`, MessageRequest: { Addresses: { [deviceToken]: { ChannelType: PushNotifications.ChannelType.GCM } }, MessageConfiguration: { GCMMessage: { RawContent: JSON.stringify({ notification: { title: "Title", body: "Test body" } }), Priority: 'medium', SilentPush: false, TimeToLive: 30, } as AWS.Pinpoint.GCMMessage } } } as AWS.Pinpoint.Types.SendMessagesRequest; logInfo('params.MessageRequest==', params.MessageRequest.MessageConfiguration) try { const data = await pinpoint.sendMessages(params).promise(); if (checkIfTokenInvalid(deviceToken, data)) { tokensTobeRemoved.push(deviceToken); } console.log("Response data==> ", JSON.stringify(data, null, 4)); logInfo('data==', deviceToken, data.MessageResponse.Result[deviceToken].DeliveryStatus) } catch (err) { logError(err, `Error while sending push notification device token ${deviceToken}`); } }) await Promise.all(pushNotificationPromises); logInfo('tokensTobeRemoved==', tokensTobeRemoved) if (tokensTobeRemoved.length) { await deleteInvalidDeviceTokens(tokensTobeRemoved); } }
2. 核心优化点
- 设备Token去重:用
[...new Set(deviceTokens)]过滤重复Token,确保同一个Token只被推送一次。 - 添加幂等性Token:在请求参数中加入
ClientRequestToken,采用用户ID-Token-时间戳的唯一组合,Pinpoint会基于该Token识别重复请求,即使服务端重试也不会重复发送。 - 统一Promise处理:移除回调函数,仅用
await ...promise()方式处理异步请求,避免逻辑冲突。 - 复用Pinpoint实例:将实例创建移出循环,减少不必要的资源消耗。
3. 额外排查步骤
- 检查
getAllDeviceTokensForUser的实现,确认是否因设备重复注册导致数据库存储重复Token。 - 查看业务日志,确认
sendPushNotification是否被意外触发多次。 - 登录Pinpoint控制台查看推送记录,确认重复推送的请求来源是否一致。
内容的提问来源于stack exchange,提问作者Lavish Patel
相关产品推荐
相关产品推荐

