使用Cloud Functions发送FCM消息失败,日志显示成功求排查
Hey there, sorry to hear your FCM notifications started acting up after working perfectly! Let’s walk through possible causes and troubleshooting steps, since your Cloud Functions logs say messages are ‘sent’ but devices aren’t receiving them (or are getting massive delays).
1. Dig into FCM’s Actual Delivery Status (Not Just Cloud Functions Logs)
Cloud Functions logging "Message sent" only means FCM accepted your request—it doesn’t guarantee delivery to the device. Your current code doesn’t log the full FCM response details, which might reveal why notifications are failing.
Update your sendToDevice handler to log the results array (this tells you exactly what happened to each token):
admin.messaging().sendToDevice(recipientDetails.device_token, payload, options) .then(function(response) { console.log("FCM Delivery Results: ", JSON.stringify(response.results)); // Flag invalid tokens for cleanup const failedTokens = []; response.results.forEach((result) => { if (result.error) { console.error('Failed to send to token:', recipientDetails.device_token, result.error); // Remove unregistered tokens from Firestore to avoid future failures if (result.error.code === 'messaging/registration-token-not-registered') { failedTokens.push(recipientDetails.device_token); } } }); // Clean up invalid tokens (optional but recommended) return Promise.all(failedTokens.map(token => db.collection('users').where('device_token', '==', token).update({device_token: null}) )); }) .catch(function(error) { console.log("Error sending message: ", error, payload); throw error; // Re-throw to mark the function as failed in logs });
Look for common errors like:
NotRegistered: The device unregistered from FCM (e.g., app reinstalled)InvalidRegistration: The token is malformed or expiredMismatchSenderId: Your app uses a different sender ID than your Cloud Functions project
2. Rule Out Firebase Infrastructure Changes
Firebase rarely breaks existing functionality without notice, but let’s check a few potential shifts:
- Runtime Version: If your function uses Node.js 14 or older, Firebase has deprecated these runtimes, which can cause performance lag or unexpected failures. Upgrade to Node 18 or 20 via the Firebase Console.
- Trigger Latency: Check Cloud Functions logs for the time between when the
messagesdocument is created and when your function starts running. If there’s a 5-10 minute gap here, it’s likely a temporary Firebase infrastructure issue—check the Firebase Status Dashboard or reach out to support. - FCM Prioritization Rules: FCM occasionally adjusts how high-priority messages are handled. For iOS, ensure you’re setting
content_available: true(your commented-out code hints at this)—iOS requires this to wake the app for data-only notifications.
3. Fix Code-Specific Issues
Looking at your current code, there are a few critical fixes that could resolve the problem:
- Return the FCM Promise: Your function returns
Promise.all([senderObj, recipientObj]), but you don’t return thesendToDevicepromise inside the.then()block. This means Cloud Functions might terminate the function before the FCM request finishes, leading to false "success" logs and incomplete delivery. Fix this by returning thesendToDevicecall:return Promise.all([senderObj, recipientObj]).then(results => { // ... build payload/options ... // Add return here! return admin.messaging().sendToDevice(recipientDetails.device_token, payload, options) .then(/* ... your logging/cleanup ... */) .catch(/* ... error handling ... */); }); - Simplify Promise Logic: You’re using an unnecessary explicit Promise constructor for
senderObjandrecipientObj—sinceget()already returns a promise. Simplify this to avoid bugs:const senderObj = senderRef.get().then(doc => { if (!doc.exists) throw new Error('No such sender document!'); return doc.data(); }).catch(err => { console.error('Failed to fetch sender data:', err); throw err; }); const recipientObj = recipientRef.get().then(doc => { if (!doc.exists) throw new Error('No such recipient document!'); return doc.data(); }).catch(err => { console.error('Failed to fetch recipient data:', err); throw err; }); - Validate Device Tokens: Add a check to ensure the recipient has a valid token before sending:
if (!recipientDetails?.device_token) { console.log('Recipient has no valid device token:', recipient); return Promise.resolve(); // Exit early to avoid wasted FCM calls }
4. Device-Specific Checks
- Android: Ask recipients to disable battery optimization for your app—Doze mode or aggressive battery saving can block high-priority FCM messages.
- iOS: Ensure the app has push notifications enabled in Settings, and the device has an active network. For data-only notifications (like your payload), iOS will only deliver them if the app is in the foreground or background unless
content_available: trueis set.
5. Escalate to Firebase Support
If you’ve tried all the above and still see issues:
- Check the Firebase Status Dashboard for ongoing outages affecting Cloud Functions or FCM.
- Reach out to Firebase Support with your project ID, function logs, and details about the delay/failure pattern.
内容的提问来源于stack exchange,提问作者Ankit Jaiswal

