-1

I'm using node.js as a backend server for sending push notification from the Firebase Cloud Messaging service. The notifications are working fine with local server but on live server, I get this error:

Error while making request: socket hang up. Error code: ECONNRESET

Things to consider are that...

  • Number of users are in the thousands on live server
  • Firebase version is firebase-admin@6.5.1
  • Previously unregistered tokens are still there. But now registered tokens are being stored.

This is my code for sending notifications:

for (let c = 0; c < tokens.length; c++) 
{
    let notifyTo = tokens[c];
    const platform = platforms[c];

    let payload;
    if (platform === "ios") {
        payload = {
            notification: {
                title: "title",
                subtitle :"messgae",
                sound: "default",
                badge: "1"
            },
            data: {
                sendFrom: "",
                notificationType: "",
                flag: "true"
            }
        };
    } else if (platform === "android") {
        payload = {
            data: {
                title: "",
                message : "",
                flag: "true"
            }
        };
    }

    const registrationtoken = notifyTo;

    await admin.messaging().sendToDevice(registrationtoken, payload)
        .then(function (response) {
            console.log("Successfully sent message:");
        })
        .catch(function (error) {
            console.log("Error sending message: ");
        });
}
samthecodingman
  • 23,122
  • 4
  • 30
  • 54

1 Answers1

2

Your issue is caused by your function taking too long to respond to the client (more than 60 seconds) and is caused by the following line:

await admin.messaging().sendToDevice(registrationtoken, payload)

Because you are waiting for each call of sendToDevice() individually, you are running your for-loop in synchronous sequential order, rather than asynchronously in parallel.

To avoid this, you want to make use of array mapping and Promise.all() which will allow you to build a queue of sendToDevice() requests. As in your current code, any failed messages will be silently ignored, but we will also count them.

Your current code makes use of two arrays, tokens and platforms, so in the code below I use a callback for Array.prototype.map() that takes two arguments - the current mapped value (from tokens) and it's index (your for-loop's c value). The index is then used to get the correct platform entry.

let fcmPromisesArray = tokens.map((token, idx) => {
    let platform = platforms[idx];

    if (platform === "ios") {
        payload = {
            notification: {
                title: "title",
                subtitle :"messgae",
                sound: "default",
                badge: "1"
            },
            data: {
                sendFrom: "",
                notificationType: "",
                flag: "true"
            }
        };
    } else if (platform === "android") {
        payload = {
            data: {
                title: "",
                message : "",
                flag: "true"
            }
        };
    }

    return admin.messaging().sendToDevice(token, payload) // note: 'await' was changed to 'return' here
        .then(function (response) {
          return true; // success
        })
        .catch(function (error) {
            console.log("Error sending message to ", token);
            return false; // failed
        });
});

let results = await Promise.all(fcmPromisesArray); // wait here for all sendToDevice() requests to finish or fail
let successCount = results.reduce((acc, v) => v ? acc + 1 : acc, 0); // this minified line just counts the number of successful results

console.log(`Successfully sent messages to ${successCount}/${results.length} devices.`);

After this snippet has run, don't forget to send a result back to the client using res.send(...) or similar.

samthecodingman
  • 23,122
  • 4
  • 30
  • 54